~ubuntu-branches/ubuntu/lucid/curl/lucid-201101212007

« back to all changes in this revision

Viewing changes to lib/ftp.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-05-16 15:16:54 UTC
  • mto: (3.1.1 lenny) (1.2.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 12.
  • Revision ID: james.westby@ubuntu.com-20070516151654-x9nkigtr2j0i8d0v
Tags: upstream-7.16.2
ImportĀ upstreamĀ versionĀ 7.16.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
 *                            | (__| |_| |  _ <| |___
6
6
 *                             \___|\___/|_| \_\_____|
7
7
 *
8
 
 * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
 
8
 * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
9
9
 *
10
10
 * This software is licensed as described in the file COPYING, which
11
11
 * you should have received as part of this distribution. The terms
18
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
19
 * KIND, either express or implied.
20
20
 *
21
 
 * $Id: ftp.c,v 1.362 2006-07-25 22:45:22 bagder Exp $
 
21
 * $Id: ftp.c,v 1.410 2007-04-11 00:25:41 danf Exp $
22
22
 ***************************************************************************/
23
23
 
24
24
#include "setup.h"
34
34
#include <unistd.h>
35
35
#endif
36
36
 
37
 
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
38
 
 
39
 
#else /* probably some kind of unix */
 
37
#ifndef WIN32
40
38
#ifdef HAVE_SYS_SOCKET_H
41
39
#include <sys/socket.h>
42
40
#endif
43
 
#include <sys/types.h>
44
41
#ifdef HAVE_NETINET_IN_H
45
42
#include <netinet/in.h>
46
43
#endif
57
54
#include <in.h>
58
55
#include <inet.h>
59
56
#endif
60
 
#endif
 
57
#endif  /* !WIN32 */
61
58
 
62
59
#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
63
60
#undef in_addr_t
75
72
#include "transfer.h"
76
73
#include "escape.h"
77
74
#include "http.h" /* for HTTP proxy tunnel stuff */
 
75
#include "socks.h"
78
76
#include "ftp.h"
79
77
 
80
78
#ifdef HAVE_KRB4
111
109
#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV
112
110
#endif
113
111
 
 
112
#ifdef CURL_DISABLE_VERBOSE_STRINGS
 
113
#define ftp_pasv_verbose(a,b,c,d)  do { } while (0)
 
114
#endif
 
115
 
114
116
/* Local API functions */
115
117
static CURLcode ftp_sendquote(struct connectdata *conn,
116
118
                              struct curl_slist *quote);
117
 
static CURLcode ftp_cwd(struct connectdata *conn, char *path);
118
 
static CURLcode ftp_mkd(struct connectdata *conn, char *path);
119
 
static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path);
120
119
static CURLcode ftp_quit(struct connectdata *conn);
121
 
static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn);
122
 
static CURLcode ftp_3rdparty_transfer(struct connectdata *conn);
123
120
static CURLcode ftp_parse_url_path(struct connectdata *conn);
124
 
static CURLcode ftp_cwd_and_create_path(struct connectdata *conn);
125
121
static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
126
 
static CURLcode ftp_3rdparty(struct connectdata *conn);
 
122
#ifndef CURL_DISABLE_VERBOSE_STRINGS
127
123
static void ftp_pasv_verbose(struct connectdata *conn,
128
124
                             Curl_addrinfo *ai,
129
125
                             char *newhost, /* ascii version */
130
126
                             int port);
 
127
#endif
131
128
static CURLcode ftp_state_post_rest(struct connectdata *conn);
132
129
static CURLcode ftp_state_post_cwd(struct connectdata *conn);
133
130
static CURLcode ftp_state_quote(struct connectdata *conn,
134
131
                                bool init, ftpstate instate);
 
132
static CURLcode ftp_nb_type(struct connectdata *conn,
 
133
                            bool ascii, ftpstate state);
 
134
static int ftp_need_type(struct connectdata *conn,
 
135
                         bool ascii);
135
136
 
136
137
/* easy-to-use macro: */
137
 
#define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
138
 
#define NBFTPSENDF(x,y,z) if((result = Curl_nbftpsendf(x,y,z))) return result
 
138
#define FTPSENDF(x,y,z)    if ((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
 
139
                              return result
 
140
#define NBFTPSENDF(x,y,z)  if ((result = Curl_nbftpsendf(x,y,z)) != CURLE_OK) \
 
141
                              return result
139
142
 
140
 
static void freedirs(struct FTP *ftp)
 
143
static void freedirs(struct connectdata *conn)
141
144
{
 
145
  struct ftp_conn *ftpc = &conn->proto.ftpc;
 
146
  struct FTP *ftp = conn->data->reqdata.proto.ftp;
 
147
 
142
148
  int i;
143
 
  if(ftp->dirs) {
144
 
    for (i=0; i < ftp->dirdepth; i++){
145
 
      if(ftp->dirs[i]) {
146
 
        free(ftp->dirs[i]);
147
 
        ftp->dirs[i]=NULL;
 
149
  if(ftpc->dirs) {
 
150
    for (i=0; i < ftpc->dirdepth; i++){
 
151
      if(ftpc->dirs[i]) {
 
152
        free(ftpc->dirs[i]);
 
153
        ftpc->dirs[i]=NULL;
148
154
      }
149
155
    }
150
 
    free(ftp->dirs);
151
 
    ftp->dirs = NULL;
 
156
    free(ftpc->dirs);
 
157
    ftpc->dirs = NULL;
152
158
  }
153
159
  if(ftp->file) {
154
160
    free(ftp->file);
164
170
*/
165
171
static bool isBadFtpString(const char *string)
166
172
{
167
 
  return strchr(string, '\r') != NULL || strchr(string, '\n') != NULL;
 
173
  return (bool)((NULL != strchr(string, '\r')) || (NULL != strchr(string, '\n')));
168
174
}
169
175
 
170
176
/***********************************************************************
182
188
  struct SessionHandle *data = conn->data;
183
189
  curl_socket_t sock = conn->sock[SECONDARYSOCKET];
184
190
  struct timeval now = Curl_tvnow();
185
 
  long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000;
 
191
  long timespent = Curl_tvdiff(Curl_tvnow(), now);
186
192
  long timeout = data->set.connecttimeout?data->set.connecttimeout:
187
193
    (data->set.timeout?data->set.timeout: 0);
188
194
 
196
202
 
197
203
  /* We allow the server 60 seconds to connect to us, or a custom timeout.
198
204
     Note the typecast here. */
199
 
  timeout_ms = (timeout?(int)timeout:60) * 1000;
 
205
  timeout_ms = (timeout?(int)timeout:60000);
200
206
 
201
 
  switch (Curl_select(sock, CURL_SOCKET_BAD, timeout_ms)) {
 
207
  switch (Curl_socket_ready(sock, CURL_SOCKET_BAD, timeout_ms)) {
202
208
  case -1: /* error */
203
209
    /* let's die here */
204
210
    failf(data, "Error while waiting for server connect");
211
217
    /* we have received data here */
212
218
    {
213
219
      curl_socket_t s = CURL_SOCKET_BAD;
214
 
      socklen_t size = (socklen_t) sizeof(struct sockaddr_in);
 
220
#ifdef ENABLE_IPV6
 
221
      struct Curl_sockaddr_storage add;
 
222
#else
215
223
      struct sockaddr_in add;
216
 
 
217
 
      if(0 == getsockname(sock, (struct sockaddr *) &add, &size))
 
224
#endif
 
225
      socklen_t size = (socklen_t) sizeof(add);
 
226
 
 
227
      if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
 
228
        size = sizeof(add);
 
229
 
218
230
        s=accept(sock, (struct sockaddr *) &add, &size);
219
 
 
 
231
      }
220
232
      sclose(sock); /* close the first socket */
221
233
 
222
234
      if (CURL_SOCKET_BAD == s) {
238
250
/* initialize stuff to prepare for reading a fresh new response */
239
251
static void ftp_respinit(struct connectdata *conn)
240
252
{
241
 
  struct FTP *ftp = conn->proto.ftp;
242
 
  ftp->nread_resp = 0;
243
 
  ftp->linestart_resp = conn->data->state.buffer;
 
253
  struct ftp_conn *ftpc = &conn->proto.ftpc;
 
254
  ftpc->nread_resp = 0;
 
255
  ftpc->linestart_resp = conn->data->state.buffer;
244
256
}
245
257
 
246
258
/* macro to check for the last line in an FTP server response */
247
 
#define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
248
 
                        isdigit((int)line[2]) && (' ' == line[3]))
 
259
#define lastline(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
 
260
                        ISDIGIT(line[2]) && (' ' == line[3]))
249
261
 
250
262
static CURLcode ftp_readresp(curl_socket_t sockfd,
251
263
                             struct connectdata *conn,
259
271
  struct SessionHandle *data = conn->data;
260
272
  char *buf = data->state.buffer;
261
273
  CURLcode result = CURLE_OK;
262
 
  struct FTP *ftp = conn->proto.ftp;
 
274
  struct ftp_conn *ftpc = &conn->proto.ftpc;
263
275
  int code = 0;
264
276
 
265
 
  if (ftpcode)
266
 
    *ftpcode = 0; /* 0 for errors or not done */
267
 
 
268
 
  ptr=buf + ftp->nread_resp;
269
 
 
270
 
  perline= (int)(ptr-ftp->linestart_resp); /* number of bytes in the current
 
277
  *ftpcode = 0; /* 0 for errors or not done */
 
278
 
 
279
  ptr=buf + ftpc->nread_resp;
 
280
 
 
281
  perline= (int)(ptr-ftpc->linestart_resp); /* number of bytes in the current
271
282
                                              line, so far */
272
283
  keepon=TRUE;
273
284
 
274
 
  while((ftp->nread_resp<BUFSIZE) && (keepon && !result)) {
 
285
  while((ftpc->nread_resp<BUFSIZE) && (keepon && !result)) {
275
286
 
276
 
    if(ftp->cache) {
 
287
    if(ftpc->cache) {
277
288
      /* we had data in the "cache", copy that instead of doing an actual
278
289
       * read
279
290
       *
282
293
       * int to begin with, even though its datatype may be larger
283
294
       * than an int.
284
295
       */
285
 
      memcpy(ptr, ftp->cache, (int)ftp->cache_size);
286
 
      gotbytes = (int)ftp->cache_size;
287
 
      free(ftp->cache);    /* free the cache */
288
 
      ftp->cache = NULL;   /* clear the pointer */
289
 
      ftp->cache_size = 0; /* zero the size just in case */
 
296
      memcpy(ptr, ftpc->cache, (int)ftpc->cache_size);
 
297
      gotbytes = (int)ftpc->cache_size;
 
298
      free(ftpc->cache);    /* free the cache */
 
299
      ftpc->cache = NULL;   /* clear the pointer */
 
300
      ftpc->cache_size = 0; /* zero the size just in case */
290
301
    }
291
302
    else {
292
 
      int res = Curl_read(conn, sockfd, ptr, BUFSIZE-ftp->nread_resp,
 
303
      int res = Curl_read(conn, sockfd, ptr, BUFSIZE-ftpc->nread_resp,
293
304
                          &gotbytes);
294
305
      if(res < 0)
295
306
        /* EWOULDBLOCK */
320
331
       * line */
321
332
      int i;
322
333
 
323
 
      conn->headerbytecount += gotbytes;
 
334
      data->reqdata.keep.headerbytecount += gotbytes;
324
335
 
325
 
      ftp->nread_resp += gotbytes;
 
336
      ftpc->nread_resp += gotbytes;
326
337
      for(i = 0; i < gotbytes; ptr++, i++) {
327
338
        perline++;
328
339
        if(*ptr=='\n') {
332
343
          /* output debug output if that is requested */
333
344
          if(data->set.verbose)
334
345
            Curl_debug(data, CURLINFO_HEADER_IN,
335
 
                       ftp->linestart_resp, perline, conn);
 
346
                       ftpc->linestart_resp, (size_t)perline, conn);
336
347
 
337
348
          /*
338
349
           * We pass all response-lines to the callback function registered
339
350
           * for "headers". The response lines can be seen as a kind of
340
351
           * headers.
341
352
           */
342
 
          result = Curl_client_write(data, CLIENTWRITE_HEADER,
343
 
                                     ftp->linestart_resp, perline);
 
353
          result = Curl_client_write(conn, CLIENTWRITE_HEADER,
 
354
                                     ftpc->linestart_resp, perline);
344
355
          if(result)
345
356
            return result;
346
357
 
347
 
          if(perline>3 && lastline(ftp->linestart_resp)) {
 
358
          if(perline>3 && lastline(ftpc->linestart_resp)) {
348
359
            /* This is the end of the last line, copy the last line to the
349
360
               start of the buffer and zero terminate, for old times sake (and
350
361
               krb4)! */
351
362
            char *meow;
352
363
            int n;
353
 
            for(meow=ftp->linestart_resp, n=0; meow<ptr; meow++, n++)
 
364
            for(meow=ftpc->linestart_resp, n=0; meow<ptr; meow++, n++)
354
365
              buf[n] = *meow;
355
366
            *meow=0; /* zero terminate */
356
367
            keepon=FALSE;
357
 
            ftp->linestart_resp = ptr+1; /* advance pointer */
 
368
            ftpc->linestart_resp = ptr+1; /* advance pointer */
358
369
            i++; /* skip this before getting out */
359
370
 
360
 
            *size = ftp->nread_resp; /* size of the response */
361
 
            ftp->nread_resp = 0; /* restart */
 
371
            *size = ftpc->nread_resp; /* size of the response */
 
372
            ftpc->nread_resp = 0; /* restart */
362
373
            break;
363
374
          }
364
375
          perline=0; /* line starts over here */
365
 
          ftp->linestart_resp = ptr+1;
 
376
          ftpc->linestart_resp = ptr+1;
366
377
        }
367
378
      }
368
379
      if(!keepon && (i != gotbytes)) {
370
381
           full chunk of data we have read from the server. We therefore need
371
382
           to store the rest of the data to be checked on the next invoke as
372
383
           it may actually contain another end of response already! */
373
 
        ftp->cache_size = gotbytes - i;
374
 
        ftp->cache = (char *)malloc((int)ftp->cache_size);
375
 
        if(ftp->cache)
376
 
          memcpy(ftp->cache, ftp->linestart_resp, (int)ftp->cache_size);
 
384
        ftpc->cache_size = gotbytes - i;
 
385
        ftpc->cache = (char *)malloc((int)ftpc->cache_size);
 
386
        if(ftpc->cache)
 
387
          memcpy(ftpc->cache, ftpc->linestart_resp, (int)ftpc->cache_size);
377
388
        else
378
389
          return CURLE_OUT_OF_MEMORY; /**BANG**/
379
390
      }
405
416
 
406
417
  *ftpcode=code; /* return the initial number like this */
407
418
 
408
 
 
409
419
  /* store the latest code for later retrieval */
410
420
  conn->data->info.httpcode=code;
411
421
 
436
446
  bool keepon=TRUE;
437
447
  ssize_t gotbytes;
438
448
  char *ptr;
439
 
  long timeout;              /* timeout in seconds */
440
 
  int interval_ms;
 
449
  long timeout;              /* timeout in milliseconds */
 
450
  long interval_ms;
441
451
  struct SessionHandle *data = conn->data;
442
452
  char *line_start;
443
453
  int code=0; /* default ftp "error code" to return */
444
454
  char *buf = data->state.buffer;
445
455
  CURLcode result = CURLE_OK;
446
 
  struct FTP *ftp = conn->proto.ftp;
 
456
  struct ftp_conn *ftpc = &conn->proto.ftpc;
447
457
  struct timeval now = Curl_tvnow();
448
458
 
449
459
  if (ftpcode)
465
475
         the response for any given ftp response, not for the time
466
476
         from connect to the given ftp response. */
467
477
      timeout = data->set.ftp_response_timeout - /* timeout time */
468
 
        Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
 
478
        Curl_tvdiff(Curl_tvnow(), now); /* spent time */
469
479
    else if(data->set.timeout)
470
480
      /* if timeout is requested, find out how much remaining time we have */
471
481
      timeout = data->set.timeout - /* timeout time */
472
 
        Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
 
482
        Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
473
483
    else
474
484
      /* Even without a requested timeout, we only wait response_time
475
485
         seconds for the full response to arrive before we bail out */
476
 
      timeout = ftp->response_time -
477
 
        Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
 
486
      timeout = ftpc->response_time -
 
487
        Curl_tvdiff(Curl_tvnow(), now); /* spent time */
478
488
 
479
489
    if(timeout <=0 ) {
480
490
      failf(data, "FTP response timeout");
481
491
      return CURLE_OPERATION_TIMEDOUT; /* already too little time */
482
492
    }
483
493
 
484
 
    if(!ftp->cache) {
 
494
    if(!ftpc->cache) {
485
495
      interval_ms = 1 * 1000;  /* use 1 second timeout intervals */
 
496
      if(timeout < interval_ms)
 
497
        interval_ms = timeout;
486
498
 
487
 
      switch (Curl_select(sockfd, CURL_SOCKET_BAD, interval_ms)) {
 
499
      switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, (int)interval_ms)) {
488
500
      case -1: /* select() error, stop reading */
489
501
        result = CURLE_RECV_ERROR;
490
 
        failf(data, "FTP response aborted due to select() error: %d",
491
 
              Curl_sockerrno());
 
502
        failf(data, "FTP response aborted due to select/poll error: %d",
 
503
              SOCKERRNO);
492
504
        break;
493
505
      case 0: /* timeout */
494
506
        if(Curl_pgrsUpdate(conn))
505
517
       * to read, but when we use Curl_read() it may do so. Do confirm
506
518
       * that this is still ok and then remove this comment!
507
519
       */
508
 
      if(ftp->cache) {
 
520
      if(ftpc->cache) {
509
521
        /* we had data in the "cache", copy that instead of doing an actual
510
522
         * read
511
523
         *
515
527
         * int to begin with, even though its datatype may be larger
516
528
         * than an int.
517
529
         */
518
 
        memcpy(ptr, ftp->cache, (int)ftp->cache_size);
519
 
        gotbytes = (int)ftp->cache_size;
520
 
        free(ftp->cache);    /* free the cache */
521
 
        ftp->cache = NULL;   /* clear the pointer */
522
 
        ftp->cache_size = 0; /* zero the size just in case */
 
530
        memcpy(ptr, ftpc->cache, (int)ftpc->cache_size);
 
531
        gotbytes = (int)ftpc->cache_size;
 
532
        free(ftpc->cache);    /* free the cache */
 
533
        ftpc->cache = NULL;   /* clear the pointer */
 
534
        ftpc->cache_size = 0; /* zero the size just in case */
523
535
      }
524
536
      else {
525
537
        int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes);
552
564
         * line */
553
565
        int i;
554
566
 
555
 
        conn->headerbytecount += gotbytes;
 
567
        data->reqdata.keep.headerbytecount += gotbytes;
556
568
 
557
569
        *nreadp += gotbytes;
558
570
        for(i = 0; i < gotbytes; ptr++, i++) {
563
575
 
564
576
            /* output debug output if that is requested */
565
577
            if(data->set.verbose)
566
 
              Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline, conn);
 
578
              Curl_debug(data, CURLINFO_HEADER_IN,
 
579
                         line_start, (size_t)perline, conn);
567
580
 
568
581
            /*
569
582
             * We pass all response-lines to the callback function registered
570
583
             * for "headers". The response lines can be seen as a kind of
571
584
             * headers.
572
585
             */
573
 
            result = Curl_client_write(data, CLIENTWRITE_HEADER,
 
586
            result = Curl_client_write(conn, CLIENTWRITE_HEADER,
574
587
                                       line_start, perline);
575
588
            if(result)
576
589
              return result;
600
613
             invoke as it may actually contain another end of response
601
614
             already!  Cleverly figured out by Eric Lavigne in December
602
615
             2001. */
603
 
          ftp->cache_size = gotbytes - i;
604
 
          ftp->cache = (char *)malloc((int)ftp->cache_size);
605
 
          if(ftp->cache)
606
 
            memcpy(ftp->cache, line_start, (int)ftp->cache_size);
 
616
          ftpc->cache_size = gotbytes - i;
 
617
          ftpc->cache = (char *)malloc((int)ftpc->cache_size);
 
618
          if(ftpc->cache)
 
619
            memcpy(ftpc->cache, line_start, (int)ftpc->cache_size);
607
620
          else
608
621
            return CURLE_OUT_OF_MEMORY; /**BANG**/
609
622
        }
646
659
static void state(struct connectdata *conn,
647
660
                  ftpstate state)
648
661
{
649
 
#ifdef CURLDEBUG
 
662
#if defined(CURLDEBUG) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
650
663
  /* for debug purposes */
651
664
  const char *names[]={
652
665
    "STOP",
657
670
    "ACCT",
658
671
    "PBSZ",
659
672
    "PROT",
 
673
    "CCC",
660
674
    "PWD",
661
675
    "QUOTE",
662
676
    "RETR_PREQUOTE",
682
696
    "QUIT"
683
697
  };
684
698
#endif
685
 
  struct FTP *ftp = conn->proto.ftp;
686
 
#ifdef CURLDEBUG
687
 
  if(ftp->state != state)
 
699
  struct ftp_conn *ftpc = &conn->proto.ftpc;
 
700
#if defined(CURLDEBUG) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
 
701
  if(ftpc->state != state)
688
702
    infof(conn->data, "FTP %p state change from %s to %s\n",
689
 
          ftp, names[ftp->state], names[state]);
 
703
          ftpc, names[ftpc->state], names[state]);
690
704
#endif
691
 
  ftp->state = state;
 
705
  ftpc->state = state;
692
706
}
693
707
 
694
708
static CURLcode ftp_state_user(struct connectdata *conn)
695
709
{
696
710
  CURLcode result;
697
 
  struct FTP *ftp = conn->proto.ftp;
 
711
  struct FTP *ftp = conn->data->reqdata.proto.ftp;
698
712
  /* send USER */
699
713
  NBFTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
700
714
 
720
734
                     curl_socket_t *socks,
721
735
                     int numsocks)
722
736
{
723
 
  struct FTP *ftp = conn->proto.ftp;
 
737
  struct ftp_conn *ftpc = &conn->proto.ftpc;
724
738
 
725
739
  if(!numsocks)
726
740
    return GETSOCK_BLANK;
727
741
 
728
742
  socks[0] = conn->sock[FIRSTSOCKET];
729
743
 
730
 
  if(ftp->sendleft) {
 
744
  if(ftpc->sendleft) {
731
745
    /* write mode */
732
746
    return GETSOCK_WRITESOCK(0);
733
747
  }
745
759
static CURLcode ftp_state_cwd(struct connectdata *conn)
746
760
{
747
761
  CURLcode result = CURLE_OK;
748
 
  struct FTP *ftp = conn->proto.ftp;
 
762
  struct ftp_conn *ftpc = &conn->proto.ftpc;
749
763
 
750
 
  if(ftp->cwddone)
 
764
  if(ftpc->cwddone)
751
765
    /* already done and fine */
752
766
    result = ftp_state_post_cwd(conn);
753
767
  else {
754
 
    ftp->count2 = 0;
755
 
    if (conn->bits.reuse && ftp->entrypath) {
 
768
    ftpc->count2 = 0;
 
769
    if (conn->bits.reuse && ftpc->entrypath) {
756
770
      /* This is a re-used connection. Since we change directory to where the
757
771
         transfer is taking place, we must first get back to the original dir
758
772
         where we ended up after login: */
759
 
      ftp->count1 = 0; /* we count this as the first path, then we add one
 
773
      ftpc->count1 = 0; /* we count this as the first path, then we add one
760
774
                          for all upcoming ones in the ftp->dirs[] array */
761
 
      NBFTPSENDF(conn, "CWD %s", ftp->entrypath);
 
775
      NBFTPSENDF(conn, "CWD %s", ftpc->entrypath);
762
776
      state(conn, FTP_CWD);
763
777
    }
764
778
    else {
765
 
      if(ftp->dirdepth) {
766
 
        ftp->count1 = 1;
 
779
      if(ftpc->dirdepth) {
 
780
        ftpc->count1 = 1;
767
781
        /* issue the first CWD, the rest is sent when the CWD responses are
768
782
           received... */
769
 
        NBFTPSENDF(conn, "CWD %s", ftp->dirs[ftp->count1 -1]);
 
783
        NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
770
784
        state(conn, FTP_CWD);
771
785
      }
772
786
      else {
789
803
 
790
804
{
791
805
  CURLcode result = CURLE_OK;
792
 
  struct FTP *ftp = conn->proto.ftp;
 
806
  struct ftp_conn *ftpc = &conn->proto.ftpc;
793
807
  struct SessionHandle *data=conn->data;
794
808
  curl_socket_t portsock= CURL_SOCKET_BAD;
795
809
  char myhost[256] = "";
827
841
       the IP from the control connection */
828
842
 
829
843
    sslen = sizeof(ss);
830
 
    rc = getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen);
831
 
    if(rc < 0) {
832
 
      failf(data, "getsockname() returned %d\n", rc);
 
844
    if (getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen)) {
 
845
      failf(data, "getsockname() failed: %s",
 
846
          Curl_strerror(conn, SOCKERRNO) );
833
847
      return CURLE_FTP_PORT_FAILED;
834
848
    }
835
849
 
 
850
    if (sslen > (socklen_t)sizeof(ss))
 
851
      sslen = sizeof(ss);
836
852
    rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL,
837
853
                     0, NIFLAGS);
838
854
    if(rc) {
839
 
      failf(data, "getnameinfo() returned %d\n", rc);
 
855
      failf(data, "getnameinfo() returned %d \n", rc);
840
856
      return CURLE_FTP_PORT_FAILED;
841
857
    }
842
858
    host = hbuf; /* use this host name */
868
884
 
869
885
    portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
870
886
    if (portsock == CURL_SOCKET_BAD) {
871
 
      error = Curl_sockerrno();
 
887
      error = SOCKERRNO;
872
888
      continue;
873
889
    }
874
890
    break;
881
897
  /* step 3, bind to a suitable local address */
882
898
 
883
899
  /* Try binding the given address. */
884
 
  if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) {
 
900
  if (bind(portsock, ai->ai_addr, ai->ai_addrlen)) {
885
901
 
886
902
    /* It failed. Bind the address used for the control connection instead */
887
903
    sslen = sizeof(ss);
888
 
 
889
904
    if (getsockname(conn->sock[FIRSTSOCKET],
890
 
                    (struct sockaddr *)sa, &sslen) < 0) {
891
 
      failf(data, "getsockname() failed");
 
905
                    (struct sockaddr *)sa, &sslen)) {
 
906
      failf(data, "getsockname() failed: %s",
 
907
          Curl_strerror(conn, SOCKERRNO) );
892
908
      sclose(portsock);
893
909
      return CURLE_FTP_PORT_FAILED;
894
910
    }
899
915
    else
900
916
      ((struct sockaddr_in6 *)sa)->sin6_port =0;
901
917
 
902
 
    if(bind(portsock, (struct sockaddr *)sa, sslen) < 0) {
903
 
      failf(data, "bind failed: %s", Curl_strerror(conn, Curl_sockerrno()));
 
918
    if (sslen > (socklen_t)sizeof(ss))
 
919
      sslen = sizeof(ss);
 
920
 
 
921
    if(bind(portsock, (struct sockaddr *)sa, sslen)) {
 
922
      failf(data, "bind failed: %s", Curl_strerror(conn, SOCKERRNO));
904
923
      sclose(portsock);
905
924
      return CURLE_FTP_PORT_FAILED;
906
925
    }
909
928
  /* get the name again after the bind() so that we can extract the
910
929
     port number it uses now */
911
930
  sslen = sizeof(ss);
912
 
  if(getsockname(portsock, (struct sockaddr *)sa, &sslen)<0) {
 
931
  if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
913
932
    failf(data, "getsockname() failed: %s",
914
 
          Curl_strerror(conn, Curl_sockerrno()) );
 
933
          Curl_strerror(conn, SOCKERRNO) );
 
934
    sclose(portsock);
915
935
    return CURLE_FTP_PORT_FAILED;
916
936
  }
917
937
 
918
938
  /* step 4, listen on the socket */
919
939
 
920
 
  if (listen(portsock, 1) < 0) {
921
 
    error = Curl_sockerrno();
 
940
  if (listen(portsock, 1)) {
 
941
    failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
922
942
    sclose(portsock);
923
 
    failf(data, "socket failure: %s", Curl_strerror(conn, error));
924
943
    return CURLE_FTP_PORT_FAILED;
925
944
  }
926
945
 
997
1016
  }
998
1017
 
999
1018
  /* store which command was sent */
1000
 
  ftp->count1 = fcmd;
 
1019
  ftpc->count1 = fcmd;
1001
1020
 
1002
1021
  /* we set the secondary socket variable to this for now, it is only so that
1003
1022
     the cleanup function will close it in case we fail before the true
1016
1035
  Curl_addrinfo *addr = NULL;
1017
1036
  unsigned short ip[4];
1018
1037
  bool freeaddr = TRUE;
 
1038
  socklen_t sslen = sizeof(sa);
1019
1039
 
1020
1040
  (void)fcmd; /* not used in the IPv4 code */
1021
1041
  if(data->set.ftpport) {
1059
1079
  if(!addr) {
1060
1080
    /* pick a suitable default here */
1061
1081
 
1062
 
    socklen_t sslen;
1063
 
 
1064
 
    sslen = sizeof(sa);
1065
1082
    if (getsockname(conn->sock[FIRSTSOCKET],
1066
 
                    (struct sockaddr *)&sa, &sslen) < 0) {
1067
 
      failf(data, "getsockname() failed");
 
1083
                    (struct sockaddr *)&sa, &sslen)) {
 
1084
      failf(data, "getsockname() failed: %s",
 
1085
          Curl_strerror(conn, SOCKERRNO) );
1068
1086
      return CURLE_FTP_PORT_FAILED;
1069
1087
    }
 
1088
    if (sslen > (socklen_t)sizeof(sa))
 
1089
      sslen = sizeof(sa);
1070
1090
 
1071
1091
    sa_filled_in = TRUE; /* the sa struct is filled in */
1072
1092
  }
1074
1094
  if (addr || sa_filled_in) {
1075
1095
    portsock = socket(AF_INET, SOCK_STREAM, 0);
1076
1096
    if(CURL_SOCKET_BAD != portsock) {
1077
 
      socklen_t size;
1078
1097
 
1079
1098
      /* we set the secondary socket variable to this for now, it
1080
1099
         is only so that the cleanup function will close it in case
1084
1103
      conn->sock[SECONDARYSOCKET] = portsock;
1085
1104
 
1086
1105
      if(!sa_filled_in) {
1087
 
        memcpy(&sa, addr->ai_addr, sizeof(sa));
 
1106
        memcpy(&sa, addr->ai_addr, sslen);
1088
1107
        sa.sin_addr.s_addr = INADDR_ANY;
1089
1108
      }
1090
1109
 
1091
1110
      sa.sin_port = 0;
1092
 
      size = sizeof(sa);
 
1111
      sslen = sizeof(sa);
1093
1112
 
1094
 
      if(bind(portsock, (struct sockaddr *)&sa, size) >= 0) {
 
1113
      if(bind(portsock, (struct sockaddr *)&sa, sslen) == 0) {
1095
1114
        /* we succeeded to bind */
1096
1115
        struct sockaddr_in add;
1097
1116
        socklen_t socksize = sizeof(add);
1098
1117
 
1099
1118
        if(getsockname(portsock, (struct sockaddr *) &add,
1100
 
                       &socksize)<0) {
1101
 
          failf(data, "getsockname() failed");
 
1119
                       &socksize)) {
 
1120
          failf(data, "getsockname() failed: %s",
 
1121
            Curl_strerror(conn, SOCKERRNO) );
1102
1122
          return CURLE_FTP_PORT_FAILED;
1103
1123
        }
1104
1124
        porttouse = ntohs(add.sin_port);
1147
1167
  if(freeaddr)
1148
1168
    Curl_freeaddrinfo(addr);
1149
1169
 
1150
 
  ftp->count1 = PORT;
 
1170
  ftpc->count1 = PORT;
1151
1171
 
1152
1172
#endif /* end of ipv4-specific code */
1153
1173
 
 
1174
  /* this tcpconnect assignment below is a hackish work-around to make the
 
1175
     multi interface with active FTP work - as it will not wait for a
 
1176
     (passive) connect in Curl_is_connected().
 
1177
 
 
1178
     The *proper* fix is to make sure that the active connection from the
 
1179
     server is done in a non-blocking way. Currently, it is still BLOCKING.
 
1180
  */
 
1181
  conn->bits.tcpconnect = TRUE;
 
1182
 
1154
1183
  state(conn, FTP_PORT);
1155
1184
  return result;
1156
1185
}
1157
1186
 
1158
1187
static CURLcode ftp_state_use_pasv(struct connectdata *conn)
1159
1188
{
1160
 
  struct FTP *ftp = conn->proto.ftp;
 
1189
  struct ftp_conn *ftpc = &conn->proto.ftpc;
1161
1190
  CURLcode result = CURLE_OK;
1162
1191
  /*
1163
1192
    Here's the excecutive summary on what to do:
1189
1218
  if(result)
1190
1219
    return result;
1191
1220
 
1192
 
  ftp->count1 = modeoff;
 
1221
  ftpc->count1 = modeoff;
1193
1222
  state(conn, FTP_PASV);
1194
1223
  infof(conn->data, "Connect data stream passively\n");
1195
1224
 
1202
1231
static CURLcode ftp_state_post_rest(struct connectdata *conn)
1203
1232
{
1204
1233
  CURLcode result = CURLE_OK;
1205
 
  struct FTP *ftp = conn->proto.ftp;
 
1234
  struct FTP *ftp = conn->data->reqdata.proto.ftp;
1206
1235
  struct SessionHandle *data = conn->data;
1207
1236
 
1208
1237
  if(ftp->no_transfer || conn->bits.no_body) {
1209
 
    /* then we're done with a "head"-like request, goto STOP */
1210
 
    state(conn, FTP_STOP);
1211
 
 
1212
1238
    /* doesn't transfer any data */
1213
1239
    ftp->no_transfer = TRUE;
 
1240
 
 
1241
    /* still possibly do PRE QUOTE jobs */
 
1242
    state(conn, FTP_RETR_PREQUOTE);
 
1243
    result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
1214
1244
  }
1215
1245
  else if(data->set.ftp_use_port) {
1216
1246
    /* We have chosen to use the PORT (or similar) command */
1226
1256
static CURLcode ftp_state_post_size(struct connectdata *conn)
1227
1257
{
1228
1258
  CURLcode result = CURLE_OK;
1229
 
  struct FTP *ftp = conn->proto.ftp;
 
1259
  struct FTP *ftp = conn->data->reqdata.proto.ftp;
1230
1260
 
1231
1261
  if(ftp->no_transfer) {
1232
1262
    /* if a "head"-like request is being made */
1246
1276
static CURLcode ftp_state_post_type(struct connectdata *conn)
1247
1277
{
1248
1278
  CURLcode result = CURLE_OK;
1249
 
  struct FTP *ftp = conn->proto.ftp;
 
1279
  struct FTP *ftp = conn->data->reqdata.proto.ftp;
1250
1280
 
1251
1281
  if(ftp->no_transfer) {
1252
1282
    /* if a "head"-like request is being made */
1306
1336
static CURLcode ftp_state_post_mdtm(struct connectdata *conn)
1307
1337
{
1308
1338
  CURLcode result = CURLE_OK;
1309
 
  struct FTP *ftp = conn->proto.ftp;
 
1339
  struct FTP *ftp = conn->data->reqdata.proto.ftp;
1310
1340
  struct SessionHandle *data = conn->data;
1311
1341
 
1312
1342
  /* If we have selected NOBODY and HEADER, it means that we only want file
1313
1343
     information. Which in FTP can't be much more than the file size and
1314
1344
     date. */
1315
 
  if(conn->bits.no_body && data->set.include_header && ftp->file) {
 
1345
  if(conn->bits.no_body && data->set.include_header && ftp->file &&
 
1346
     ftp_need_type(conn, data->set.prefer_ascii)) {
1316
1347
    /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
1317
1348
       may not support it! It is however the only way we have to get a file's
1318
1349
       size! */
1321
1352
 
1322
1353
    /* Some servers return different sizes for different modes, and thus we
1323
1354
       must set the proper type before we check the size */
1324
 
    NBFTPSENDF(conn, "TYPE %c",
1325
 
               data->set.ftp_ascii?'A':'I');
1326
 
    state(conn, FTP_TYPE);
1327
 
    /* keep track of our current transfer type */
1328
 
    data->ftp_in_ascii_mode = data->set.ftp_ascii;
 
1355
    result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
 
1356
    if (result)
 
1357
      return result;
1329
1358
  }
1330
1359
  else
1331
1360
    result = ftp_state_post_type(conn);
1338
1367
static CURLcode ftp_state_post_cwd(struct connectdata *conn)
1339
1368
{
1340
1369
  CURLcode result = CURLE_OK;
1341
 
  struct FTP *ftp = conn->proto.ftp;
 
1370
  struct FTP *ftp = conn->data->reqdata.proto.ftp;
1342
1371
  struct SessionHandle *data = conn->data;
1343
1372
 
1344
1373
  /* Requested time of file or time-depended transfer? */
1362
1391
                                   bool sizechecked)
1363
1392
{
1364
1393
  CURLcode result = CURLE_OK;
1365
 
  struct FTP *ftp = conn->proto.ftp;
 
1394
  struct FTP *ftp = conn->data->reqdata.proto.ftp;
1366
1395
  struct SessionHandle *data = conn->data;
1367
1396
  curl_off_t passed=0;
1368
1397
 
1369
 
  if((conn->resume_from && !sizechecked) ||
1370
 
     ((conn->resume_from > 0) && sizechecked)) {
 
1398
  if((data->reqdata.resume_from && !sizechecked) ||
 
1399
     ((data->reqdata.resume_from > 0) && sizechecked)) {
1371
1400
    /* we're about to continue the uploading of a file */
1372
1401
    /* 1. get already existing file's size. We use the SIZE command for this
1373
1402
       which may not exist in the server!  The SIZE command is not in
1381
1410
    /* 4. lower the infilesize counter */
1382
1411
    /* => transfer as usual */
1383
1412
 
1384
 
    if(conn->resume_from < 0 ) {
 
1413
    if(data->reqdata.resume_from < 0 ) {
1385
1414
      /* Got no given size to start from, figure it out */
1386
1415
      NBFTPSENDF(conn, "SIZE %s", ftp->file);
1387
1416
      state(conn, FTP_STOR_SIZE);
1398
1427
    /* TODO: allow the ioctlfunction to provide a fast forward function that
1399
1428
       can be used here and use this method only as a fallback! */
1400
1429
    do {
1401
 
      curl_off_t readthisamountnow = (conn->resume_from - passed);
 
1430
      curl_off_t readthisamountnow = (data->reqdata.resume_from - passed);
1402
1431
      curl_off_t actuallyread;
1403
1432
 
1404
1433
      if(readthisamountnow > BUFSIZE)
1414
1443
              " bytes from the input", passed);
1415
1444
        return CURLE_FTP_COULDNT_USE_REST;
1416
1445
      }
1417
 
    } while(passed != conn->resume_from);
 
1446
    } while(passed != data->reqdata.resume_from);
1418
1447
 
1419
1448
    /* now, decrease the size of the read */
1420
1449
    if(data->set.infilesize>0) {
1421
 
      data->set.infilesize -= conn->resume_from;
 
1450
      data->set.infilesize -= data->reqdata.resume_from;
1422
1451
 
1423
1452
      if(data->set.infilesize <= 0) {
1424
1453
        infof(data, "File already completely uploaded\n");
1425
1454
 
1426
1455
        /* no data to transfer */
1427
 
        result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
 
1456
        result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1428
1457
 
1429
1458
        /* Set no_transfer so that we won't get any error in
1430
1459
         * Curl_ftp_done() because we didn't transfer anything! */
1450
1479
                                ftpstate instate)
1451
1480
{
1452
1481
  CURLcode result = CURLE_OK;
1453
 
  struct FTP *ftp = conn->proto.ftp;
1454
1482
  struct SessionHandle *data = conn->data;
 
1483
  struct FTP *ftp = data->reqdata.proto.ftp;
 
1484
  struct ftp_conn *ftpc = &conn->proto.ftpc;
1455
1485
  bool quote=FALSE;
1456
1486
  struct curl_slist *item;
1457
1487
 
1470
1500
  }
1471
1501
 
1472
1502
  if(init)
1473
 
    ftp->count1 = 0;
 
1503
    ftpc->count1 = 0;
1474
1504
  else
1475
 
    ftp->count1++;
 
1505
    ftpc->count1++;
1476
1506
 
1477
1507
  if(item) {
1478
1508
    int i = 0;
1479
1509
 
1480
1510
    /* Skip count1 items in the linked list */
1481
 
    while((i< ftp->count1) && item) {
 
1511
    while((i< ftpc->count1) && item) {
1482
1512
      item = item->next;
1483
1513
      i++;
1484
1514
    }
1497
1527
      result = ftp_state_cwd(conn);
1498
1528
      break;
1499
1529
    case FTP_RETR_PREQUOTE:
1500
 
      NBFTPSENDF(conn, "SIZE %s", ftp->file);
1501
 
      state(conn, FTP_RETR_SIZE);
 
1530
      if (ftp->no_transfer)
 
1531
        state(conn, FTP_STOP);
 
1532
      else {
 
1533
        NBFTPSENDF(conn, "SIZE %s", ftp->file);
 
1534
        state(conn, FTP_RETR_SIZE);
 
1535
      }
1502
1536
      break;
1503
1537
    case FTP_STOR_PREQUOTE:
1504
1538
      result = ftp_state_ul_setup(conn, FALSE);
1514
1548
static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
1515
1549
                                    int ftpcode)
1516
1550
{
1517
 
  struct FTP *ftp = conn->proto.ftp;
 
1551
  struct ftp_conn *ftpc = &conn->proto.ftpc;
1518
1552
  CURLcode result;
1519
1553
  struct SessionHandle *data=conn->data;
1520
1554
  Curl_addrinfo *conninfo;
1530
1564
  char newhost[NEWHOST_BUFSIZE];
1531
1565
  char *str=&data->state.buffer[4];  /* start on the first letter */
1532
1566
 
1533
 
  if((ftp->count1 == 0) &&
 
1567
  if((ftpc->count1 == 0) &&
1534
1568
     (ftpcode == 229)) {
1535
1569
    /* positive EPSV response */
1536
1570
    char *ptr = strchr(str, '(');
1556
1590
          }
1557
1591
        }
1558
1592
        if(ptr) {
1559
 
          newport = num;
 
1593
          newport = (unsigned short)(num & 0xffff);
1560
1594
 
1561
1595
          if (conn->bits.tunnel_proxy)
1562
1596
            /* proxy tunnel -> use other host info because ip_addr_str is the
1575
1609
      return CURLE_FTP_WEIRD_PASV_REPLY;
1576
1610
    }
1577
1611
  }
1578
 
  else if((ftp->count1 == 1) &&
 
1612
  else if((ftpc->count1 == 1) &&
1579
1613
          (ftpcode == 227)) {
1580
1614
    /* positive PASV response */
1581
1615
    int ip[4];
1620
1654
    else
1621
1655
      snprintf(newhost, sizeof(newhost),
1622
1656
               "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
1623
 
    newport = (port[0]<<8) + port[1];
 
1657
    newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
1624
1658
  }
1625
 
  else if(ftp->count1 == 0) {
 
1659
  else if(ftpc->count1 == 0) {
1626
1660
    /* EPSV failed, move on to PASV */
1627
1661
 
1628
1662
    /* disable it for next transfer */
1630
1664
    infof(data, "disabling EPSV usage\n");
1631
1665
 
1632
1666
    NBFTPSENDF(conn, "PASV", NULL);
1633
 
    ftp->count1++;
 
1667
    ftpc->count1++;
1634
1668
    /* remain in the FTP_PASV state */
1635
1669
    return result;
1636
1670
  }
1639
1673
    return CURLE_FTP_WEIRD_PASV_REPLY;
1640
1674
  }
1641
1675
 
1642
 
  if(data->change.proxy && *data->change.proxy) {
 
1676
  if(data->set.proxy && *data->set.proxy) {
1643
1677
    /*
1644
1678
     * This is a tunnel through a http proxy and we need to connect to the
1645
1679
     * proxy again here.
1678
1712
 
1679
1713
  Curl_resolv_unlock(data, addr); /* we're done using this address */
1680
1714
 
1681
 
  if (result && ftp->count1 == 0 && ftpcode == 229) {
 
1715
  if (result && ftpc->count1 == 0 && ftpcode == 229) {
1682
1716
    infof(data, "got positive EPSV response, but can't connect. "
1683
1717
          "Disabling EPSV\n");
1684
1718
    /* disable it for next transfer */
1685
1719
    conn->bits.ftp_use_epsv = FALSE;
1686
1720
    data->state.errorbuf = FALSE; /* allow error message to get rewritten */
1687
1721
    NBFTPSENDF(conn, "PASV", NULL);
1688
 
    ftp->count1++;
 
1722
    ftpc->count1++;
1689
1723
    /* remain in the FTP_PASV state */
1690
1724
    return result;
1691
1725
 }
1705
1739
    /* this just dumps information about this second connection */
1706
1740
    ftp_pasv_verbose(conn, conninfo, newhost, connectport);
1707
1741
 
 
1742
  switch(data->set.proxytype) {
 
1743
  case CURLPROXY_SOCKS5:
 
1744
    result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport,
 
1745
                         SECONDARYSOCKET, conn);
 
1746
    break;
 
1747
  case CURLPROXY_HTTP:
 
1748
    /* do nothing here. handled later. */
 
1749
    break;
 
1750
  case CURLPROXY_SOCKS4:
 
1751
    result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
 
1752
                         SECONDARYSOCKET, conn);
 
1753
    break;
 
1754
  default:
 
1755
    failf(data, "unknown proxytype option given");
 
1756
    result = CURLE_COULDNT_CONNECT;
 
1757
    break;
 
1758
  }
1708
1759
#ifndef CURL_DISABLE_HTTP
1709
1760
  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
1710
1761
    /* FIX: this MUST wait for a proper connect first if 'connected' is
1720
1771
     * FTP pointer
1721
1772
     */
1722
1773
    struct HTTP http_proxy;
1723
 
    struct FTP *ftp_save = conn->proto.ftp;
 
1774
    struct FTP *ftp_save = data->reqdata.proto.ftp;
1724
1775
    memset(&http_proxy, 0, sizeof(http_proxy));
1725
 
    conn->proto.http = &http_proxy;
 
1776
    data->reqdata.proto.http = &http_proxy;
1726
1777
 
1727
1778
    result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
1728
1779
 
1729
 
    conn->proto.ftp = ftp_save;
 
1780
    data->reqdata.proto.ftp = ftp_save;
1730
1781
 
1731
1782
    if(CURLE_OK != result)
1732
1783
      return result;
1741
1792
static CURLcode ftp_state_port_resp(struct connectdata *conn,
1742
1793
                                    int ftpcode)
1743
1794
{
1744
 
  struct FTP *ftp = conn->proto.ftp;
1745
1795
  struct SessionHandle *data = conn->data;
1746
 
  ftpport fcmd = (ftpport)ftp->count1;
 
1796
  struct ftp_conn *ftpc = &conn->proto.ftpc;
 
1797
  ftpport fcmd = (ftpport)ftpc->count1;
1747
1798
  CURLcode result = CURLE_OK;
1748
1799
 
1749
1800
  if(ftpcode != 200) {
1775
1826
                                    int ftpcode)
1776
1827
{
1777
1828
  CURLcode result = CURLE_OK;
1778
 
  struct FTP *ftp = conn->proto.ftp;
1779
1829
  struct SessionHandle *data=conn->data;
 
1830
  struct FTP *ftp = data->reqdata.proto.ftp;
1780
1831
 
1781
1832
  switch(ftpcode) {
1782
1833
  case 213:
1823
1874
                 tm->tm_hour,
1824
1875
                 tm->tm_min,
1825
1876
                 tm->tm_sec);
1826
 
        result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
 
1877
        result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
1827
1878
        if(result)
1828
1879
          return result;
1829
1880
      } /* end of a ridiculous amount of conditionals */
1906
1957
{
1907
1958
  CURLcode result = CURLE_OK;
1908
1959
  struct SessionHandle *data=conn->data;
1909
 
  struct FTP *ftp = conn->proto.ftp;
 
1960
  struct FTP *ftp = data->reqdata.proto.ftp;
1910
1961
 
1911
1962
  if (data->set.max_filesize && (filesize > data->set.max_filesize)) {
1912
1963
    failf(data, "Maximum file size exceeded");
1914
1965
  }
1915
1966
  ftp->downloadsize = filesize;
1916
1967
 
1917
 
  if(conn->resume_from) {
 
1968
  if(data->reqdata.resume_from) {
1918
1969
    /* We always (attempt to) get the size of downloads, so it is done before
1919
1970
       this even when not doing resumes. */
1920
1971
    if(filesize == -1) {
1927
1978
    else {
1928
1979
      /* We got a file size report, so we check that there actually is a
1929
1980
         part of the file left to get, or else we go home.  */
1930
 
      if(conn->resume_from< 0) {
 
1981
      if(data->reqdata.resume_from< 0) {
1931
1982
        /* We're supposed to download the last abs(from) bytes */
1932
 
        if(filesize < -conn->resume_from) {
 
1983
        if(filesize < -data->reqdata.resume_from) {
1933
1984
          failf(data, "Offset (%" FORMAT_OFF_T
1934
1985
                ") was beyond file size (%" FORMAT_OFF_T ")",
1935
 
                conn->resume_from, filesize);
 
1986
                data->reqdata.resume_from, filesize);
1936
1987
          return CURLE_BAD_DOWNLOAD_RESUME;
1937
1988
        }
1938
1989
        /* convert to size to download */
1939
 
        ftp->downloadsize = -conn->resume_from;
 
1990
        ftp->downloadsize = -data->reqdata.resume_from;
1940
1991
        /* download from where? */
1941
 
        conn->resume_from = filesize - ftp->downloadsize;
 
1992
        data->reqdata.resume_from = filesize - ftp->downloadsize;
1942
1993
      }
1943
1994
      else {
1944
 
        if(filesize < conn->resume_from) {
 
1995
        if(filesize < data->reqdata.resume_from) {
1945
1996
          failf(data, "Offset (%" FORMAT_OFF_T
1946
1997
                ") was beyond file size (%" FORMAT_OFF_T ")",
1947
 
                conn->resume_from, filesize);
 
1998
                data->reqdata.resume_from, filesize);
1948
1999
          return CURLE_BAD_DOWNLOAD_RESUME;
1949
2000
        }
1950
2001
        /* Now store the number of bytes we are expected to download */
1951
 
        ftp->downloadsize = filesize-conn->resume_from;
 
2002
        ftp->downloadsize = filesize-data->reqdata.resume_from;
1952
2003
      }
1953
2004
    }
1954
2005
 
1955
2006
    if(ftp->downloadsize == 0) {
1956
2007
      /* no data to transfer */
1957
 
      result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
 
2008
      result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1958
2009
      infof(data, "File already completely downloaded\n");
1959
2010
 
1960
2011
      /* Set no_transfer so that we won't get any error in Curl_ftp_done()
1966
2017
 
1967
2018
    /* Set resume file transfer offset */
1968
2019
    infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
1969
 
          "\n", conn->resume_from);
 
2020
          "\n", data->reqdata.resume_from);
1970
2021
 
1971
 
    NBFTPSENDF(conn, "REST %" FORMAT_OFF_T, conn->resume_from);
 
2022
    NBFTPSENDF(conn, "REST %" FORMAT_OFF_T, data->reqdata.resume_from);
1972
2023
 
1973
2024
    state(conn, FTP_RETR_REST);
1974
2025
 
1998
2049
    if(-1 != filesize) {
1999
2050
      snprintf(buf, sizeof(data->state.buffer),
2000
2051
               "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
2001
 
      result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
 
2052
      result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
2002
2053
      if(result)
2003
2054
        return result;
2004
2055
    }
2007
2058
  else if(instate == FTP_RETR_SIZE)
2008
2059
    result = ftp_state_post_retr_size(conn, filesize);
2009
2060
  else if(instate == FTP_STOR_SIZE) {
2010
 
    conn->resume_from = filesize;
 
2061
    data->reqdata.resume_from = filesize;
2011
2062
    result = ftp_state_ul_setup(conn, TRUE);
2012
2063
  }
2013
2064
 
2019
2070
                                    ftpstate instate)
2020
2071
{
2021
2072
  CURLcode result = CURLE_OK;
2022
 
  struct FTP *ftp = conn->proto.ftp;
 
2073
  struct FTP *ftp = conn->data->reqdata.proto.ftp;
2023
2074
 
2024
2075
  switch(instate) {
2025
2076
  case FTP_REST:
2026
2077
  default:
2027
2078
    if (ftpcode == 350) {
2028
 
      result = Curl_client_write(conn->data, CLIENTWRITE_BOTH,
 
2079
      result = Curl_client_write(conn, CLIENTWRITE_BOTH,
2029
2080
                               (char *)"Accept-ranges: bytes\r\n", 0);
2030
2081
      if(result)
2031
2082
        return result;
2054
2105
{
2055
2106
  CURLcode result = CURLE_OK;
2056
2107
  struct SessionHandle *data = conn->data;
2057
 
  struct FTP *ftp = conn->proto.ftp;
 
2108
  struct FTP *ftp = data->reqdata.proto.ftp;
2058
2109
 
2059
2110
  if(ftpcode>=400) {
2060
2111
    failf(data, "Failed FTP upload: %0d", ftpcode);
2087
2138
 
2088
2139
  Curl_pgrsSetUploadSize(data, data->set.infilesize);
2089
2140
 
2090
 
  result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
2091
 
                         SECONDARYSOCKET, ftp->bytecountp);
 
2141
  result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
 
2142
                               SECONDARYSOCKET, ftp->bytecountp);
2092
2143
  state(conn, FTP_STOP);
2093
2144
 
2094
2145
  return result;
2101
2152
{
2102
2153
  CURLcode result = CURLE_OK;
2103
2154
  struct SessionHandle *data = conn->data;
2104
 
  struct FTP *ftp = conn->proto.ftp;
 
2155
  struct FTP *ftp = data->reqdata.proto.ftp;
2105
2156
  char *buf = data->state.buffer;
2106
2157
 
2107
2158
  if((ftpcode == 150) || (ftpcode == 125)) {
2136
2187
     */
2137
2188
 
2138
2189
    if((instate != FTP_LIST) &&
2139
 
       !data->set.ftp_ascii &&
 
2190
       !data->set.prefer_ascii &&
2140
2191
       (ftp->downloadsize < 1)) {
2141
2192
      /*
2142
2193
       * It seems directory listings either don't show the size or very
2155
2206
          if('(' == *bytes)
2156
2207
            break;
2157
2208
          /* skip only digits */
2158
 
          if(!isdigit((int)*bytes)) {
 
2209
          if(!ISDIGIT(*bytes)) {
2159
2210
            bytes=NULL;
2160
2211
            break;
2161
2212
          }
2188
2239
        return result;
2189
2240
    }
2190
2241
 
2191
 
    if(size > conn->maxdownload && conn->maxdownload > 0)
2192
 
      size = conn->size = conn->maxdownload;
 
2242
    if(size > data->reqdata.maxdownload && data->reqdata.maxdownload > 0)
 
2243
      size = data->reqdata.size = data->reqdata.maxdownload;
 
2244
 
 
2245
    infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->reqdata.maxdownload);
2193
2246
 
2194
2247
    if(instate != FTP_LIST)
2195
2248
      infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
2196
2249
 
2197
2250
    /* FTP download: */
2198
 
    result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE,
2199
 
                         ftp->bytecountp,
2200
 
                         -1, NULL); /* no upload here */
 
2251
    result=Curl_setup_transfer(conn, SECONDARYSOCKET, size, FALSE,
 
2252
                               ftp->bytecountp,
 
2253
                               -1, NULL); /* no upload here */
2201
2254
    if(result)
2202
2255
      return result;
2203
2256
 
2274
2327
{
2275
2328
  CURLcode result = CURLE_OK;
2276
2329
  struct SessionHandle *data = conn->data;
2277
 
  struct FTP *ftp = conn->proto.ftp;
 
2330
  struct FTP *ftp = data->reqdata.proto.ftp;
 
2331
  struct ftp_conn *ftpc = &conn->proto.ftpc;
2278
2332
  (void)instate; /* no use for this yet */
2279
2333
 
2280
 
  if((ftpcode == 331) && (ftp->state == FTP_USER)) {
 
2334
  if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
2281
2335
    /* 331 Password required for ...
2282
2336
       (the server requires to send the user's password too) */
2283
2337
    NBFTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
2343
2397
  curl_socket_t sock = conn->sock[FIRSTSOCKET];
2344
2398
  struct SessionHandle *data=conn->data;
2345
2399
  int ftpcode;
2346
 
  struct FTP *ftp = conn->proto.ftp;
 
2400
  struct ftp_conn *ftpc = &conn->proto.ftpc;
2347
2401
  static const char * const ftpauth[]  = {
2348
2402
    "SSL", "TLS"
2349
2403
  };
2350
2404
  size_t nread = 0;
2351
2405
 
2352
 
  if(ftp->sendleft) {
 
2406
  if(ftpc->sendleft) {
2353
2407
    /* we have a piece of a command still left to send */
2354
2408
    ssize_t written;
2355
 
    result = Curl_write(conn, sock, ftp->sendthis + ftp->sendsize -
2356
 
                        ftp->sendleft, ftp->sendleft, &written);
 
2409
    result = Curl_write(conn, sock, ftpc->sendthis + ftpc->sendsize -
 
2410
                        ftpc->sendleft, ftpc->sendleft, &written);
2357
2411
    if(result)
2358
2412
      return result;
2359
2413
 
2360
 
    if(written != (ssize_t)ftp->sendleft) {
 
2414
    if(written != (ssize_t)ftpc->sendleft) {
2361
2415
      /* only a fraction was sent */
2362
 
      ftp->sendleft -= written;
 
2416
      ftpc->sendleft -= written;
2363
2417
    }
2364
2418
    else {
2365
 
      free(ftp->sendthis);
2366
 
      ftp->sendthis=NULL;
2367
 
      ftp->sendleft = ftp->sendsize = 0;
2368
 
      ftp->response = Curl_tvnow();
 
2419
      free(ftpc->sendthis);
 
2420
      ftpc->sendthis=NULL;
 
2421
      ftpc->sendleft = ftpc->sendsize = 0;
 
2422
      ftpc->response = Curl_tvnow();
2369
2423
    }
2370
2424
    return CURLE_OK;
2371
2425
  }
2377
2431
 
2378
2432
  if(ftpcode) {
2379
2433
    /* we have now received a full FTP server response */
2380
 
    switch(ftp->state) {
 
2434
    switch(ftpc->state) {
2381
2435
    case FTP_WAIT220:
2382
2436
      if(ftpcode != 220) {
2383
2437
        failf(data, "This doesn't seem like a nice ftp-server response");
2406
2460
        /* We don't have a SSL/TLS connection yet, but FTPS is
2407
2461
           requested. Try a FTPS connection now */
2408
2462
 
2409
 
        ftp->count3=0;
 
2463
        ftpc->count3=0;
2410
2464
        switch(data->set.ftpsslauth) {
2411
2465
        case CURLFTPAUTH_DEFAULT:
2412
2466
        case CURLFTPAUTH_SSL:
2413
 
          ftp->count2 = 1; /* add one to get next */
2414
 
          ftp->count1 = 0;
 
2467
          ftpc->count2 = 1; /* add one to get next */
 
2468
          ftpc->count1 = 0;
2415
2469
          break;
2416
2470
        case CURLFTPAUTH_TLS:
2417
 
          ftp->count2 = -1; /* subtract one to get next */
2418
 
          ftp->count1 = 1;
 
2471
          ftpc->count2 = -1; /* subtract one to get next */
 
2472
          ftpc->count1 = 1;
2419
2473
          break;
2420
2474
        default:
2421
2475
          failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d\n",
2422
2476
                data->set.ftpsslauth);
2423
2477
          return CURLE_FAILED_INIT; /* we don't know what to do */
2424
2478
        }
2425
 
        NBFTPSENDF(conn, "AUTH %s", ftpauth[ftp->count1]);
 
2479
        NBFTPSENDF(conn, "AUTH %s", ftpauth[ftpc->count1]);
2426
2480
        state(conn, FTP_AUTH);
2427
2481
      }
2428
2482
      else {
2452
2506
          result = ftp_state_user(conn);
2453
2507
        }
2454
2508
      }
2455
 
      else if(ftp->count3 < 1) {
2456
 
        ftp->count3++;
2457
 
        ftp->count1 += ftp->count2; /* get next attempt */
2458
 
        result = Curl_nbftpsendf(conn, "AUTH %s", ftpauth[ftp->count1]);
 
2509
      else if(ftpc->count3 < 1) {
 
2510
        ftpc->count3++;
 
2511
        ftpc->count1 += ftpc->count2; /* get next attempt */
 
2512
        result = Curl_nbftpsendf(conn, "AUTH %s", ftpauth[ftpc->count1]);
2459
2513
        /* remain in this same state */
2460
2514
      }
2461
2515
      else {
2473
2527
 
2474
2528
    case FTP_USER:
2475
2529
    case FTP_PASS:
2476
 
      result = ftp_state_user_resp(conn, ftpcode, ftp->state);
 
2530
      result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
2477
2531
      break;
2478
2532
 
2479
2533
    case FTP_ACCT:
2506
2560
      if(ftpcode/100 == 2)
2507
2561
        /* We have enabled SSL for the data connection! */
2508
2562
        conn->ssl[SECONDARYSOCKET].use =
2509
 
          data->set.ftp_ssl != CURLFTPSSL_CONTROL;
 
2563
          (bool)(data->set.ftp_ssl != CURLFTPSSL_CONTROL);
2510
2564
      /* FTP servers typically responds with 500 if they decide to reject
2511
2565
         our 'P' request */
2512
2566
      else if(data->set.ftp_ssl> CURLFTPSSL_CONTROL)
2513
2567
        /* we failed and bails out */
2514
2568
        return CURLE_FTP_SSL_FAILED;
2515
2569
 
 
2570
      if(data->set.ftp_ccc) {
 
2571
        /* CCC - Clear Command Channel
 
2572
         */
 
2573
        NBFTPSENDF(conn, "CCC", NULL);
 
2574
        state(conn, FTP_CCC);
 
2575
      }
 
2576
      else {
 
2577
        result = ftp_state_pwd(conn);
 
2578
        if(result)
 
2579
          return result;
 
2580
      }
 
2581
      break;
 
2582
 
 
2583
    case FTP_CCC:
 
2584
      if (ftpcode < 500) {
 
2585
        /* First shut down the SSL layer (note: this call will block) */
 
2586
        result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
 
2587
 
 
2588
        if(result) {
 
2589
          failf(conn->data, "Failed to clear the command channel (CCC)");
 
2590
          return result;
 
2591
        }
 
2592
      }
 
2593
 
 
2594
      /* Then continue as normal */
2516
2595
      result = ftp_state_pwd(conn);
2517
2596
      if(result)
2518
2597
        return result;
2556
2635
            store++;
2557
2636
            ptr++;
2558
2637
          }
2559
 
          ftp->entrypath =dir; /* remember this */
2560
 
          infof(data, "Entry path is '%s'\n", ftp->entrypath);
 
2638
          ftpc->entrypath =dir; /* remember this */
 
2639
          infof(data, "Entry path is '%s'\n", ftpc->entrypath);
2561
2640
          /* also save it where getinfo can access it: */
2562
 
          data->state.most_recent_ftp_entrypath = ftp->entrypath;
 
2641
          data->state.most_recent_ftp_entrypath = ftpc->entrypath;
2563
2642
        }
2564
2643
        else {
2565
2644
          /* couldn't get the path */
2579
2658
        failf(conn->data, "QUOT command failed with %03d", ftpcode);
2580
2659
        return CURLE_FTP_QUOTE_ERROR;
2581
2660
      }
2582
 
      result = ftp_state_quote(conn, FALSE, ftp->state);
 
2661
      result = ftp_state_quote(conn, FALSE, ftpc->state);
2583
2662
      if(result)
2584
2663
        return result;
2585
2664
 
2589
2668
      if(ftpcode/100 != 2) {
2590
2669
        /* failure to CWD there */
2591
2670
        if(conn->data->set.ftp_create_missing_dirs &&
2592
 
           ftp->count1 && !ftp->count2) {
 
2671
           ftpc->count1 && !ftpc->count2) {
2593
2672
          /* try making it */
2594
 
          ftp->count2++; /* counter to prevent CWD-MKD loops */
2595
 
          NBFTPSENDF(conn, "MKD %s", ftp->dirs[ftp->count1 - 1]);
 
2673
          ftpc->count2++; /* counter to prevent CWD-MKD loops */
 
2674
          NBFTPSENDF(conn, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
2596
2675
          state(conn, FTP_MKD);
2597
2676
        }
2598
2677
        else {
2599
2678
          /* return failure */
2600
2679
          failf(data, "Server denied you to change to the given directory");
2601
 
          ftp->cwdfail = TRUE; /* don't remember this path as we failed
2602
 
                                  to enter it */
 
2680
          ftpc->cwdfail = TRUE; /* don't remember this path as we failed
 
2681
                                   to enter it */
2603
2682
          return CURLE_FTP_ACCESS_DENIED;
2604
2683
        }
2605
2684
      }
2606
2685
      else {
2607
2686
        /* success */
2608
 
        ftp->count2=0;
2609
 
        if(++ftp->count1 <= ftp->dirdepth) {
 
2687
        ftpc->count2=0;
 
2688
        if(++ftpc->count1 <= ftpc->dirdepth) {
2610
2689
          /* send next CWD */
2611
 
          NBFTPSENDF(conn, "CWD %s", ftp->dirs[ftp->count1 - 1]);
 
2690
          NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
2612
2691
        }
2613
2692
        else {
2614
2693
          result = ftp_state_post_cwd(conn);
2626
2705
      }
2627
2706
      state(conn, FTP_CWD);
2628
2707
      /* send CWD */
2629
 
      NBFTPSENDF(conn, "CWD %s", ftp->dirs[ftp->count1 - 1]);
 
2708
      NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
2630
2709
      break;
2631
2710
 
2632
2711
    case FTP_MDTM:
2637
2716
    case FTP_LIST_TYPE:
2638
2717
    case FTP_RETR_TYPE:
2639
2718
    case FTP_STOR_TYPE:
2640
 
      result = ftp_state_type_resp(conn, ftpcode, ftp->state);
 
2719
      result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
2641
2720
      break;
2642
2721
 
2643
2722
    case FTP_SIZE:
2644
2723
    case FTP_RETR_SIZE:
2645
2724
    case FTP_STOR_SIZE:
2646
 
      result = ftp_state_size_resp(conn, ftpcode, ftp->state);
 
2725
      result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
2647
2726
      break;
2648
2727
 
2649
2728
    case FTP_REST:
2650
2729
    case FTP_RETR_REST:
2651
 
      result = ftp_state_rest_resp(conn, ftpcode, ftp->state);
 
2730
      result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
2652
2731
      break;
2653
2732
 
2654
2733
    case FTP_PASV:
2661
2740
 
2662
2741
    case FTP_LIST:
2663
2742
    case FTP_RETR:
2664
 
      result = ftp_state_get_resp(conn, ftpcode, ftp->state);
 
2743
      result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
2665
2744
      break;
2666
2745
 
2667
2746
    case FTP_STOR:
2685
2764
static long ftp_state_timeout(struct connectdata *conn)
2686
2765
{
2687
2766
  struct SessionHandle *data=conn->data;
2688
 
  struct FTP *ftp = conn->proto.ftp;
 
2767
  struct ftp_conn *ftpc = &conn->proto.ftpc;
2689
2768
  long timeout_ms=360000; /* in milliseconds */
2690
2769
 
2691
2770
  if(data->set.ftp_response_timeout )
2693
2772
       time.  Also, use ftp->response because FTP_RESPONSE_TIMEOUT is supposed
2694
2773
       to govern the response for any given ftp response, not for the time
2695
2774
       from connect to the given ftp response. */
2696
 
    timeout_ms = data->set.ftp_response_timeout*1000 - /* timeout time */
2697
 
      Curl_tvdiff(Curl_tvnow(), ftp->response); /* spent time */
 
2775
    timeout_ms = data->set.ftp_response_timeout - /* timeout time */
 
2776
      Curl_tvdiff(Curl_tvnow(), ftpc->response); /* spent time */
2698
2777
  else if(data->set.timeout)
2699
2778
    /* if timeout is requested, find out how much remaining time we have */
2700
 
    timeout_ms = data->set.timeout*1000 - /* timeout time */
 
2779
    timeout_ms = data->set.timeout - /* timeout time */
2701
2780
      Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
2702
2781
  else
2703
2782
    /* Without a requested timeout, we only wait 'response_time' seconds for
2704
2783
       the full response to arrive before we bail out */
2705
 
    timeout_ms = ftp->response_time*1000 -
2706
 
      Curl_tvdiff(Curl_tvnow(), ftp->response); /* spent time */
 
2784
    timeout_ms = ftpc->response_time -
 
2785
      Curl_tvdiff(Curl_tvnow(), ftpc->response); /* spent time */
2707
2786
 
2708
2787
  return timeout_ms;
2709
2788
}
2716
2795
  curl_socket_t sock = conn->sock[FIRSTSOCKET];
2717
2796
  int rc;
2718
2797
  struct SessionHandle *data=conn->data;
2719
 
  struct FTP *ftp = conn->proto.ftp;
 
2798
  struct ftp_conn *ftpc = &conn->proto.ftpc;
2720
2799
  CURLcode result = CURLE_OK;
2721
2800
  long timeout_ms = ftp_state_timeout(conn);
2722
2801
 
2727
2806
    return CURLE_OPERATION_TIMEDOUT;
2728
2807
  }
2729
2808
 
2730
 
  rc = Curl_select(ftp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
2731
 
                   ftp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
 
2809
  rc = Curl_socket_ready(ftpc->sendleft?CURL_SOCKET_BAD:sock, /* reading */
 
2810
                   ftpc->sendleft?sock:CURL_SOCKET_BAD, /* writing */
2732
2811
                   0);
2733
2812
 
2734
2813
  if(rc == -1) {
2735
 
    failf(data, "select error");
 
2814
    failf(data, "select/poll error");
2736
2815
    return CURLE_OUT_OF_MEMORY;
2737
2816
  }
2738
2817
  else if(rc != 0) {
2739
2818
    result = ftp_statemach_act(conn);
2740
 
    *done = (ftp->state == FTP_STOP);
 
2819
    *done = (bool)(ftpc->state == FTP_STOP);
2741
2820
  }
2742
2821
  /* if rc == 0, then select() timed out */
2743
2822
 
2749
2828
  curl_socket_t sock = conn->sock[FIRSTSOCKET];
2750
2829
  int rc;
2751
2830
  struct SessionHandle *data=conn->data;
2752
 
  struct FTP *ftp = conn->proto.ftp;
 
2831
  struct ftp_conn *ftpc = &conn->proto.ftpc;
2753
2832
  CURLcode result = CURLE_OK;
2754
2833
 
2755
 
  while(ftp->state != FTP_STOP) {
 
2834
  while(ftpc->state != FTP_STOP) {
2756
2835
    long timeout_ms = ftp_state_timeout(conn);
2757
2836
 
2758
2837
    if(timeout_ms <=0 ) {
2760
2839
      return CURLE_OPERATION_TIMEDOUT; /* already too little time */
2761
2840
    }
2762
2841
 
2763
 
    rc = Curl_select(ftp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
2764
 
                     ftp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
 
2842
    rc = Curl_socket_ready(ftpc->sendleft?CURL_SOCKET_BAD:sock, /* reading */
 
2843
                     ftpc->sendleft?sock:CURL_SOCKET_BAD, /* writing */
2765
2844
                     (int)timeout_ms);
2766
2845
 
2767
2846
    if(rc == -1) {
2768
 
      failf(data, "select error");
 
2847
      failf(data, "select/poll error");
2769
2848
      return CURLE_OUT_OF_MEMORY;
2770
2849
    }
2771
2850
    else if(rc == 0) {
2783
2862
}
2784
2863
 
2785
2864
/*
 
2865
 * Allocate and initialize the struct FTP for the current SessionHandle.  If
 
2866
 * need be.
 
2867
 */
 
2868
static CURLcode ftp_init(struct connectdata *conn)
 
2869
{
 
2870
  struct SessionHandle *data = conn->data;
 
2871
  struct FTP *ftp;
 
2872
  if(data->reqdata.proto.ftp)
 
2873
    return CURLE_OK;
 
2874
 
 
2875
  ftp = (struct FTP *)calloc(sizeof(struct FTP), 1);
 
2876
  if(!ftp)
 
2877
    return CURLE_OUT_OF_MEMORY;
 
2878
 
 
2879
  data->reqdata.proto.ftp = ftp;
 
2880
 
 
2881
  /* get some initial data into the ftp struct */
 
2882
  ftp->bytecountp = &data->reqdata.keep.bytecount;
 
2883
 
 
2884
  /* no need to duplicate them, this connectdata struct won't change */
 
2885
  ftp->user = conn->user;
 
2886
  ftp->passwd = conn->passwd;
 
2887
  if (isBadFtpString(ftp->user) || isBadFtpString(ftp->passwd))
 
2888
    return CURLE_URL_MALFORMAT;
 
2889
 
 
2890
  return CURLE_OK;
 
2891
}
 
2892
 
 
2893
/*
2786
2894
 * Curl_ftp_connect() should do everything that is to be considered a part of
2787
2895
 * the connection phase.
2788
2896
 *
2793
2901
CURLcode Curl_ftp_connect(struct connectdata *conn,
2794
2902
                          bool *done) /* see description above */
2795
2903
{
2796
 
  struct FTP *ftp;
2797
2904
  CURLcode result;
2798
2905
#ifndef CURL_DISABLE_HTTP
2799
2906
  /* for FTP over HTTP proxy */
2800
2907
  struct HTTP http_proxy;
2801
2908
  struct FTP *ftp_save;
2802
2909
#endif   /* CURL_DISABLE_HTTP */
 
2910
  struct ftp_conn *ftpc = &conn->proto.ftpc;
 
2911
  struct SessionHandle *data=conn->data;
2803
2912
 
2804
2913
  *done = FALSE; /* default to not done yet */
2805
2914
 
2806
 
  ftp = (struct FTP *)calloc(sizeof(struct FTP), 1);
2807
 
  if(!ftp)
2808
 
    return CURLE_OUT_OF_MEMORY;
 
2915
  if (data->reqdata.proto.ftp) {
 
2916
    Curl_ftp_disconnect(conn);
 
2917
    free(data->reqdata.proto.ftp);
 
2918
    data->reqdata.proto.ftp = NULL;
 
2919
  }
2809
2920
 
2810
 
  conn->proto.ftp = ftp;
 
2921
  result = ftp_init(conn);
 
2922
  if(result)
 
2923
    return result;
2811
2924
 
2812
2925
  /* We always support persistant connections on ftp */
2813
2926
  conn->bits.close = FALSE;
2814
2927
 
2815
 
  /* get some initial data into the ftp struct */
2816
 
  ftp->bytecountp = &conn->bytecount;
2817
 
 
2818
 
  /* no need to duplicate them, this connectdata struct won't change */
2819
 
  ftp->user = conn->user;
2820
 
  ftp->passwd = conn->passwd;
2821
 
  if (isBadFtpString(ftp->user) || isBadFtpString(ftp->passwd))
2822
 
    return CURLE_URL_MALFORMAT;
2823
 
 
2824
 
  ftp->response_time = 3600; /* set default response time-out */
 
2928
  ftpc->response_time = 3600000; /* set default response time-out */
2825
2929
 
2826
2930
#ifndef CURL_DISABLE_HTTP
2827
2931
  if (conn->bits.tunnel_proxy && conn->bits.httpproxy) {
2834
2938
     * Curl_proxyCONNECT we have to set back the member to the original struct
2835
2939
     * FTP pointer
2836
2940
     */
2837
 
    ftp_save = conn->proto.ftp;
 
2941
    ftp_save = data->reqdata.proto.ftp;
2838
2942
    memset(&http_proxy, 0, sizeof(http_proxy));
2839
 
    conn->proto.http = &http_proxy;
 
2943
    data->reqdata.proto.http = &http_proxy;
2840
2944
 
2841
2945
    result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
2842
2946
                               conn->host.name, conn->remote_port);
2843
2947
 
2844
 
    conn->proto.ftp = ftp_save;
 
2948
    data->reqdata.proto.ftp = ftp_save;
2845
2949
 
2846
2950
    if(CURLE_OK != result)
2847
2951
      return result;
2861
2965
     response */
2862
2966
  ftp_respinit(conn); /* init the response reader stuff */
2863
2967
  state(conn, FTP_WAIT220);
2864
 
  ftp->response = Curl_tvnow(); /* start response time-out now! */
 
2968
  ftpc->response = Curl_tvnow(); /* start response time-out now! */
2865
2969
 
2866
 
  if(conn->data->state.used_interface == Curl_if_multi)
 
2970
  if(data->state.used_interface == Curl_if_multi)
2867
2971
    result = Curl_ftp_multi_statemach(conn, done);
2868
2972
  else {
2869
2973
    result = ftp_easy_statemach(conn);
2883
2987
 *
2884
2988
 * Input argument is already checked for validity.
2885
2989
 */
2886
 
CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
 
2990
CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status, bool premature)
2887
2991
{
2888
2992
  struct SessionHandle *data = conn->data;
2889
 
  struct FTP *ftp = conn->proto.ftp;
 
2993
  struct FTP *ftp = data->reqdata.proto.ftp;
 
2994
  struct ftp_conn *ftpc = &conn->proto.ftpc;
2890
2995
  ssize_t nread;
2891
2996
  int ftpcode;
2892
2997
  CURLcode result=CURLE_OK;
2893
 
  bool was_ctl_valid = ftp->ctl_valid;
 
2998
  bool was_ctl_valid = ftpc->ctl_valid;
2894
2999
  size_t flen;
2895
3000
  size_t dlen;
2896
3001
  char *path;
2897
 
 
2898
 
  /* now store a copy of the directory we are in */
2899
 
  if(ftp->prevpath)
2900
 
    free(ftp->prevpath);
2901
 
 
2902
 
  /* get the "raw" path */
2903
 
  path = curl_easy_unescape(conn->data, conn->path, 0, NULL);
2904
 
  if(!path)
2905
 
    return CURLE_OUT_OF_MEMORY;
2906
 
 
2907
 
  flen = ftp->file?strlen(ftp->file):0; /* file is "raw" already */
2908
 
  dlen = strlen(path)-flen;
2909
 
  if(dlen && !ftp->cwdfail) {
2910
 
    ftp->prevpath = path;
2911
 
    if(flen)
2912
 
      /* if 'path' is not the whole string */
2913
 
      ftp->prevpath[dlen]=0; /* terminate */
2914
 
    infof(data, "Remembering we are in dir %s\n", ftp->prevpath);
2915
 
  }
2916
 
  else {
2917
 
    ftp->prevpath = NULL; /* no path */
2918
 
    free(path);
2919
 
  }
2920
 
  /* free the dir tree and file parts */
2921
 
  freedirs(ftp);
 
3002
  char *path_to_use = data->reqdata.path;
 
3003
  struct Curl_transfer_keeper *k = &data->reqdata.keep;
 
3004
 
 
3005
  if(!ftp)
 
3006
    /* When the easy handle is removed from the multi while libcurl is still
 
3007
     * trying to resolve the host name, it seems that the ftp struct is not
 
3008
     * yet initialized, but the removal action calls Curl_done() which calls
 
3009
     * this function. So we simply return success if no ftp pointer is set.
 
3010
     */
 
3011
    return CURLE_OK;
2922
3012
 
2923
3013
  switch(status) {
2924
3014
  case CURLE_BAD_DOWNLOAD_RESUME:
2926
3016
  case CURLE_FTP_PORT_FAILED:
2927
3017
  case CURLE_FTP_COULDNT_SET_BINARY:
2928
3018
  case CURLE_FTP_COULDNT_RETR_FILE:
 
3019
  case CURLE_FTP_COULDNT_STOR_FILE:
2929
3020
  case CURLE_FTP_ACCESS_DENIED:
 
3021
  case CURLE_FILESIZE_EXCEEDED:
2930
3022
    /* the connection stays alive fine even though this happened */
2931
3023
    /* fall-through */
2932
3024
  case CURLE_OK: /* doesn't affect the control connection's status */
2933
 
    ftp->ctl_valid = was_ctl_valid;
2934
 
    break;
 
3025
    if (!premature) {
 
3026
      ftpc->ctl_valid = was_ctl_valid;
 
3027
      break;
 
3028
    }
 
3029
    /* until we cope better with prematurely ended requests, let them
 
3030
     * fallback as if in complete failure */
2935
3031
  default:       /* by default, an error means the control connection is
2936
3032
                    wedged and should not be used anymore */
2937
 
    ftp->ctl_valid = FALSE;
 
3033
    ftpc->ctl_valid = FALSE;
 
3034
    ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
 
3035
                             current path, as this connection is going */
 
3036
    conn->bits.close = TRUE; /* marked for closure */
2938
3037
    break;
2939
3038
  }
2940
3039
 
 
3040
  /* now store a copy of the directory we are in */
 
3041
  if(ftpc->prevpath)
 
3042
    free(ftpc->prevpath);
 
3043
 
 
3044
  /* get the "raw" path */
 
3045
  path = curl_easy_unescape(data, path_to_use, 0, NULL);
 
3046
  if(!path)
 
3047
    return CURLE_OUT_OF_MEMORY;
 
3048
 
 
3049
  flen = ftp->file?strlen(ftp->file):0; /* file is "raw" already */
 
3050
  dlen = strlen(path)-flen;
 
3051
  if(dlen && !ftpc->cwdfail) {
 
3052
    ftpc->prevpath = path;
 
3053
    if(flen)
 
3054
      /* if 'path' is not the whole string */
 
3055
      ftpc->prevpath[dlen]=0; /* terminate */
 
3056
    infof(data, "Remembering we are in dir %s\n", ftpc->prevpath);
 
3057
  }
 
3058
  else {
 
3059
    ftpc->prevpath = NULL; /* no path */
 
3060
    free(path);
 
3061
  }
 
3062
  /* free the dir tree and file parts */
 
3063
  freedirs(conn);
 
3064
 
2941
3065
#ifdef HAVE_KRB4
2942
3066
  Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
2943
3067
#endif
2952
3076
 
2953
3077
  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
2954
3078
 
2955
 
  if(!ftp->no_transfer && !status) {
 
3079
  if(!ftp->no_transfer && !status && !premature) {
2956
3080
    /*
2957
3081
     * Let's see what the server says about the transfer we just performed,
2958
3082
     * but lower the timeout as sometimes this connection has died while the
2959
3083
     * data has been transfered. This happens when doing through NATs etc that
2960
3084
     * abandon old silent connections.
2961
3085
     */
2962
 
    long old_time = ftp->response_time;
 
3086
    long old_time = ftpc->response_time;
2963
3087
 
2964
 
    ftp->response_time = 60; /* give it only a minute for now */
 
3088
    ftpc->response_time = 60000; /* give it only a minute for now */
2965
3089
 
2966
3090
    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
2967
3091
 
2968
 
    ftp->response_time = old_time; /* set this back to previous value */
 
3092
    ftpc->response_time = old_time; /* set this back to previous value */
2969
3093
 
2970
3094
    if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
2971
3095
      failf(data, "control connection looks dead");
2972
 
      ftp->ctl_valid = FALSE; /* mark control connection as bad */
 
3096
      ftpc->ctl_valid = FALSE; /* mark control connection as bad */
2973
3097
      return result;
2974
3098
    }
2975
3099
 
2976
3100
    if(result)
2977
3101
      return result;
2978
3102
 
2979
 
    if(!ftp->dont_check) {
 
3103
    if(!ftpc->dont_check) {
2980
3104
      /* 226 Transfer complete, 250 Requested file action okay, completed. */
2981
3105
      if((ftpcode != 226) && (ftpcode != 250)) {
2982
3106
        failf(data, "server did not report OK, got %d", ftpcode);
2985
3109
    }
2986
3110
  }
2987
3111
 
2988
 
  if(result)
 
3112
  if(result || premature)
2989
3113
    /* the response code from the transfer showed an error already so no
2990
3114
       use checking further */
2991
3115
    ;
3001
3125
    }
3002
3126
  }
3003
3127
  else {
3004
 
    if((-1 != conn->size) && (conn->size != *ftp->bytecountp) &&
 
3128
    if((-1 != k->size) && (k->size != *ftp->bytecountp) &&
3005
3129
#ifdef CURL_DO_LINEEND_CONV
3006
3130
       /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
3007
3131
        * we'll check to see if the discrepancy can be explained by the number
3008
3132
        * of CRLFs we've changed to LFs.
3009
3133
        */
3010
 
       ((conn->size + data->state.crlf_conversions) != *ftp->bytecountp) &&
 
3134
       ((k->size + data->state.crlf_conversions) != *ftp->bytecountp) &&
3011
3135
#endif /* CURL_DO_LINEEND_CONV */
3012
 
       (conn->maxdownload != *ftp->bytecountp)) {
 
3136
       (k->maxdownload != *ftp->bytecountp)) {
3013
3137
      failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
3014
3138
            *ftp->bytecountp);
3015
3139
      result = CURLE_PARTIAL_FILE;
3016
3140
    }
3017
 
    else if(!ftp->dont_check &&
 
3141
    else if(!ftpc->dont_check &&
3018
3142
            !*ftp->bytecountp &&
3019
 
            (conn->size>0)) {
 
3143
            (k->size>0)) {
3020
3144
      failf(data, "No data was received!");
3021
3145
      result = CURLE_FTP_COULDNT_RETR_FILE;
3022
3146
    }
3024
3148
 
3025
3149
  /* clear these for next connection */
3026
3150
  ftp->no_transfer = FALSE;
3027
 
  ftp->dont_check = FALSE;
3028
 
 
3029
 
  if (!result && conn->sec_conn) {   /* 3rd party transfer */
3030
 
    /* "done" with the secondary connection */
3031
 
    result = Curl_ftp_done(conn->sec_conn, status);
3032
 
  }
 
3151
  ftpc->dont_check = FALSE;
3033
3152
 
3034
3153
  /* Send any post-transfer QUOTE strings? */
3035
 
  if(!status && !result && data->set.postquote)
 
3154
  if(!status && !result && !premature && data->set.postquote)
3036
3155
    result = ftp_sendquote(conn, data->set.postquote);
3037
3156
 
3038
3157
  return result;
3077
3196
 
3078
3197
/***********************************************************************
3079
3198
 *
3080
 
 * ftp_transfertype()
3081
 
 *
3082
 
 * Set transfer type. We only deal with ASCII or BINARY so this function
 
3199
 * ftp_need_type()
 
3200
 *
 
3201
 * Returns TRUE if we in the current situation should send TYPE
 
3202
 */
 
3203
static int ftp_need_type(struct connectdata *conn,
 
3204
                         bool ascii_wanted)
 
3205
{
 
3206
  return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
 
3207
}
 
3208
 
 
3209
/***********************************************************************
 
3210
 *
 
3211
 * ftp_nb_type()
 
3212
 *
 
3213
 * Set TYPE. We only deal with ASCII or BINARY so this function
3083
3214
 * sets one of them.
 
3215
 * If the transfer type is not sent, simulate on OK response in newstate
3084
3216
 */
3085
 
static CURLcode ftp_transfertype(struct connectdata *conn,
3086
 
                                  bool ascii)
 
3217
static CURLcode ftp_nb_type(struct connectdata *conn,
 
3218
                            bool ascii, ftpstate newstate)
3087
3219
{
3088
 
  struct SessionHandle *data = conn->data;
3089
 
  int ftpcode;
3090
 
  ssize_t nread;
 
3220
  struct ftp_conn *ftpc = &conn->proto.ftpc;
3091
3221
  CURLcode result;
3092
 
 
3093
 
  FTPSENDF(conn, "TYPE %s", ascii?"A":"I");
3094
 
 
3095
 
  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3096
 
  if(result)
3097
 
    return result;
3098
 
 
3099
 
  if(ftpcode != 200) {
3100
 
    failf(data, "Couldn't set %s mode",
3101
 
          ascii?"ASCII":"binary");
3102
 
    return ascii? CURLE_FTP_COULDNT_SET_ASCII:CURLE_FTP_COULDNT_SET_BINARY;
 
3222
  int want = ascii?'A':'I';
 
3223
 
 
3224
  if (ftpc->transfertype == want) {
 
3225
    state(conn, newstate);
 
3226
    return ftp_state_type_resp(conn, 200, newstate);
3103
3227
  }
 
3228
 
 
3229
  NBFTPSENDF(conn, "TYPE %c", want);
 
3230
  state(conn, newstate);
 
3231
 
3104
3232
  /* keep track of our current transfer type */
3105
 
  data->ftp_in_ascii_mode = ascii;
3106
 
 
 
3233
  ftpc->transfertype = (char)want;
3107
3234
  return CURLE_OK;
3108
3235
}
3109
3236
 
3116
3243
 * possibly new IP address.
3117
3244
 *
3118
3245
 */
 
3246
#ifndef CURL_DISABLE_VERBOSE_STRINGS
3119
3247
static void
3120
3248
ftp_pasv_verbose(struct connectdata *conn,
3121
3249
                 Curl_addrinfo *ai,
3126
3254
  Curl_printable_address(ai, buf, sizeof(buf));
3127
3255
  infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
3128
3256
}
 
3257
#endif
3129
3258
 
3130
3259
/*
3131
3260
  Check if this is a range download, and if so, set the internal variables
3138
3267
  curl_off_t totalsize=-1;
3139
3268
  char *ptr;
3140
3269
  char *ptr2;
3141
 
  struct FTP *ftp = conn->proto.ftp;
 
3270
  struct SessionHandle *data = conn->data;
 
3271
  struct ftp_conn *ftpc = &conn->proto.ftpc;
3142
3272
 
3143
 
  if(conn->bits.use_range && conn->range) {
3144
 
    from=curlx_strtoofft(conn->range, &ptr, 0);
3145
 
    while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
 
3273
  if(data->reqdata.use_range && data->reqdata.range) {
 
3274
    from=curlx_strtoofft(data->reqdata.range, &ptr, 0);
 
3275
    while(ptr && *ptr && (ISSPACE(*ptr) || (*ptr=='-')))
3146
3276
      ptr++;
3147
3277
    to=curlx_strtoofft(ptr, &ptr2, 0);
3148
3278
    if(ptr == ptr2) {
3151
3281
    }
3152
3282
    if((-1 == to) && (from>=0)) {
3153
3283
      /* X - */
3154
 
      conn->resume_from = from;
 
3284
      data->reqdata.resume_from = from;
3155
3285
      DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n",
3156
3286
                   from));
3157
3287
    }
3158
3288
    else if(from < 0) {
3159
3289
      /* -Y */
3160
3290
      totalsize = -from;
3161
 
      conn->maxdownload = -from;
3162
 
      conn->resume_from = from;
 
3291
      data->reqdata.maxdownload = -from;
 
3292
      data->reqdata.resume_from = from;
3163
3293
      DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
3164
3294
                   totalsize));
3165
3295
    }
3166
3296
    else {
3167
3297
      /* X-Y */
3168
3298
      totalsize = to-from;
3169
 
      conn->maxdownload = totalsize+1; /* include the last mentioned byte */
3170
 
      conn->resume_from = from;
 
3299
      data->reqdata.maxdownload = totalsize+1; /* include last byte */
 
3300
      data->reqdata.resume_from = from;
3171
3301
      DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
3172
3302
                   " getting %" FORMAT_OFF_T " bytes\n",
3173
 
                   from, conn->maxdownload));
 
3303
                   from, data->reqdata.maxdownload));
3174
3304
    }
3175
3305
    DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T
3176
3306
                 " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
3177
 
                 from, to, conn->maxdownload));
3178
 
    ftp->dont_check = TRUE; /* dont check for successful transfer */
 
3307
                 from, to, data->reqdata.maxdownload));
 
3308
    ftpc->dont_check = TRUE; /* dont check for successful transfer */
3179
3309
  }
 
3310
  else
 
3311
    data->reqdata.maxdownload = -1;
3180
3312
  return CURLE_OK;
3181
3313
}
3182
3314
 
3194
3326
  CURLcode result = CURLE_OK;
3195
3327
 
3196
3328
  /* the ftp struct is inited in Curl_ftp_connect() */
3197
 
  struct FTP *ftp = conn->proto.ftp;
 
3329
  struct FTP *ftp = data->reqdata.proto.ftp;
3198
3330
 
3199
3331
  DEBUGF(infof(data, "DO-MORE phase starts\n"));
3200
3332
 
3202
3334
    /* a transfer is about to take place */
3203
3335
 
3204
3336
    if(data->set.upload) {
3205
 
      NBFTPSENDF(conn, "TYPE %c", data->set.ftp_ascii?'A':'I');
3206
 
      state(conn, FTP_STOR_TYPE);
3207
 
      /* keep track of our current transfer type */
3208
 
      data->ftp_in_ascii_mode = data->set.ftp_ascii;
 
3337
      result = ftp_nb_type(conn, data->set.prefer_ascii,
 
3338
                                      FTP_STOR_TYPE);
 
3339
      if (result)
 
3340
        return result;
3209
3341
    }
3210
3342
    else {
3211
3343
      /* download */
3218
3350
        /* The specified path ends with a slash, and therefore we think this
3219
3351
           is a directory that is requested, use LIST. But before that we
3220
3352
           need to set ASCII transfer mode. */
3221
 
        NBFTPSENDF(conn, "TYPE A", NULL);
3222
 
        state(conn, FTP_LIST_TYPE);
3223
 
        /* keep track of our current transfer type */
3224
 
        data->ftp_in_ascii_mode = 1;
 
3353
        result = ftp_nb_type(conn, 1, FTP_LIST_TYPE);
 
3354
        if (result)
 
3355
          return result;
3225
3356
      }
3226
3357
      else {
3227
 
        NBFTPSENDF(conn, "TYPE %c", data->set.ftp_ascii?'A':'I');
3228
 
        state(conn, FTP_RETR_TYPE);
3229
 
        /* keep track of our current transfer type */
3230
 
        data->ftp_in_ascii_mode = data->set.ftp_ascii;
 
3358
        result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
 
3359
        if (result)
 
3360
          return result;
3231
3361
      }
3232
3362
    }
3233
3363
    result = ftp_easy_statemach(conn);
3236
3366
  if(ftp->no_transfer)
3237
3367
    /* no data to transfer. FIX: it feels like a kludge to have this here
3238
3368
       too! */
3239
 
    result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
 
3369
    result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3240
3370
 
3241
3371
  /* end of transfer */
3242
 
  DEBUGF(infof(data, "DO-MORE phase ends\n"));
 
3372
  DEBUGF(infof(data, "DO-MORE phase ends with %d\n", result));
3243
3373
 
3244
3374
  return result;
3245
3375
}
3301
3431
 
3302
3432
  *done = FALSE; /* default to false */
3303
3433
 
 
3434
  /*
 
3435
    Since connections can be re-used between SessionHandles, this might be a
 
3436
    connection already existing but on a fresh SessionHandle struct so we must
 
3437
    make sure we have a good 'struct FTP' to play with. For new connections,
 
3438
    the struct FTP is allocated and setup in the Curl_ftp_connect() function.
 
3439
  */
 
3440
  retcode = ftp_init(conn);
 
3441
  if(retcode)
 
3442
    return retcode;
 
3443
 
3304
3444
  retcode = ftp_parse_url_path(conn);
3305
3445
  if (retcode)
3306
3446
    return retcode;
3307
3447
 
3308
 
  if (conn->sec_conn) {
3309
 
    /* 3rd party transfer */
3310
 
    *done = TRUE; /* BLOCKING */
3311
 
    retcode = ftp_3rdparty(conn);
3312
 
  }
3313
 
  else
3314
 
    retcode = ftp_regular_transfer(conn, done);
 
3448
  retcode = ftp_regular_transfer(conn, done);
3315
3449
 
3316
3450
  return retcode;
3317
3451
}
3335
3469
  size_t write_len;
3336
3470
  char *sptr=s;
3337
3471
  CURLcode res = CURLE_OK;
3338
 
  struct FTP *ftp = conn->proto.ftp;
3339
3472
  struct SessionHandle *data = conn->data;
 
3473
  struct ftp_conn *ftpc = &conn->proto.ftpc;
3340
3474
 
3341
3475
  va_list ap;
3342
3476
  va_start(ap, fmt);
3365
3499
    return res;
3366
3500
 
3367
3501
  if(conn->data->set.verbose)
3368
 
    Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written,
3369
 
               conn);
 
3502
    Curl_debug(conn->data, CURLINFO_HEADER_OUT,
 
3503
               sptr, (size_t)bytes_written, conn);
3370
3504
 
3371
3505
  if(bytes_written != (ssize_t)write_len) {
3372
3506
    /* the whole chunk was not sent, store the rest of the data */
3373
3507
    write_len -= bytes_written;
3374
3508
    sptr += bytes_written;
3375
 
    ftp->sendthis = malloc(write_len);
3376
 
    if(ftp->sendthis) {
3377
 
      memcpy(ftp->sendthis, sptr, write_len);
3378
 
      ftp->sendsize=ftp->sendleft=write_len;
 
3509
    ftpc->sendthis = malloc(write_len);
 
3510
    if(ftpc->sendthis) {
 
3511
      memcpy(ftpc->sendthis, sptr, write_len);
 
3512
      ftpc->sendsize = ftpc->sendleft = write_len;
3379
3513
    }
3380
3514
    else {
3381
3515
      failf(data, "out of memory");
3383
3517
    }
3384
3518
  }
3385
3519
  else
3386
 
    ftp->response = Curl_tvnow();
 
3520
    ftpc->response = Curl_tvnow();
3387
3521
 
3388
3522
  return res;
3389
3523
}
3423
3557
      break;
3424
3558
 
3425
3559
    if(conn->data->set.verbose)
3426
 
      Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written, conn);
 
3560
      Curl_debug(conn->data, CURLINFO_HEADER_OUT,
 
3561
                 sptr, (size_t)bytes_written, conn);
3427
3562
 
3428
3563
    if(bytes_written != (ssize_t)write_len) {
3429
3564
      write_len -= bytes_written;
3450
3585
{
3451
3586
  CURLcode result = CURLE_OK;
3452
3587
 
3453
 
  if(conn->proto.ftp->ctl_valid) {
 
3588
  if(conn->proto.ftpc.ctl_valid) {
3454
3589
    NBFTPSENDF(conn, "QUIT", NULL);
3455
3590
    state(conn, FTP_QUIT);
3456
3591
 
3469
3604
 */
3470
3605
CURLcode Curl_ftp_disconnect(struct connectdata *conn)
3471
3606
{
3472
 
  struct FTP *ftp= conn->proto.ftp;
 
3607
  struct ftp_conn *ftpc= &conn->proto.ftpc;
3473
3608
 
3474
3609
  /* We cannot send quit unconditionally. If this connection is stale or
3475
3610
     bad in any way, sending quit and waiting around here will make the
3480
3615
  */
3481
3616
 
3482
3617
  /* The FTP session may or may not have been allocated/setup at this point! */
3483
 
  if(ftp) {
 
3618
  if(conn->data->reqdata.proto.ftp) {
3484
3619
    (void)ftp_quit(conn); /* ignore errors on the QUIT */
3485
3620
 
3486
 
    if(ftp->entrypath) {
 
3621
    if(ftpc->entrypath) {
3487
3622
      struct SessionHandle *data = conn->data;
3488
3623
      data->state.most_recent_ftp_entrypath = NULL;
3489
 
      free(ftp->entrypath);
3490
 
      ftp->entrypath = NULL;
3491
 
    }
3492
 
    if(ftp->cache) {
3493
 
      free(ftp->cache);
3494
 
      ftp->cache = NULL;
3495
 
    }
3496
 
    freedirs(ftp);
3497
 
    if(ftp->prevpath) {
3498
 
      free(ftp->prevpath);
3499
 
      ftp->prevpath = NULL;
3500
 
    }
3501
 
  }
3502
 
  return CURLE_OK;
3503
 
}
3504
 
 
3505
 
/***********************************************************************
3506
 
 *
3507
 
 * ftp_mkd()
3508
 
 *
3509
 
 * Makes a directory on the FTP server.
3510
 
 *
3511
 
 * Calls failf()
3512
 
 */
3513
 
static CURLcode ftp_mkd(struct connectdata *conn, char *path)
3514
 
{
3515
 
  CURLcode result=CURLE_OK;
3516
 
  int ftpcode; /* for ftp status */
3517
 
  ssize_t nread;
3518
 
 
3519
 
  /* Create a directory on the remote server */
3520
 
  FTPSENDF(conn, "MKD %s", path);
3521
 
 
3522
 
  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3523
 
  if(result)
3524
 
    return result;
3525
 
 
3526
 
  switch(ftpcode) {
3527
 
  case 257:
3528
 
    /* success! */
3529
 
    infof( conn->data , "Created remote directory %s\n" , path );
3530
 
    break;
3531
 
  case 550:
3532
 
    failf(conn->data, "Permission denied to make directory %s", path);
3533
 
    result = CURLE_FTP_ACCESS_DENIED;
3534
 
    break;
3535
 
  default:
3536
 
    failf(conn->data, "unrecognized MKD response: %d", ftpcode );
3537
 
    result = CURLE_FTP_ACCESS_DENIED;
3538
 
    break;
3539
 
  }
3540
 
  return  result;
3541
 
}
3542
 
 
3543
 
/***********************************************************************
3544
 
 *
3545
 
 * ftp_cwd()
3546
 
 *
3547
 
 * Send 'CWD' to the remote server to Change Working Directory.  It is the ftp
3548
 
 * version of the unix 'cd' command. This function is only called from the
3549
 
 * ftp_cwd_and_mkd() function these days.
3550
 
 *
3551
 
 * This function does NOT call failf().
3552
 
 */
3553
 
static
3554
 
CURLcode ftp_cwd(struct connectdata *conn, char *path)
3555
 
{
3556
 
  ssize_t nread;
3557
 
  int     ftpcode;
3558
 
  CURLcode result;
3559
 
 
3560
 
  FTPSENDF(conn, "CWD %s", path);
3561
 
  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3562
 
  if (!result) {
3563
 
    /* According to RFC959, CWD is supposed to return 250 on success, but
3564
 
       there seem to be non-compliant FTP servers out there that return 200,
3565
 
       so we accept any '2xy' code here. */
3566
 
    if (ftpcode/100 != 2)
3567
 
      result = CURLE_FTP_ACCESS_DENIED;
3568
 
  }
3569
 
 
3570
 
  return result;
3571
 
}
3572
 
 
3573
 
/***********************************************************************
3574
 
 *
3575
 
 * ftp_cwd_and_mkd()
3576
 
 *
3577
 
 * Change to the given directory.  If the directory is not present, and we
3578
 
 * have been told to allow it, then create the directory and cd to it.
3579
 
 *
3580
 
 */
3581
 
static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
3582
 
{
3583
 
  CURLcode result;
3584
 
 
3585
 
  result = ftp_cwd(conn, path);
3586
 
  if (result) {
3587
 
    if(conn->data->set.ftp_create_missing_dirs) {
3588
 
      result = ftp_mkd(conn, path);
3589
 
      if (result)
3590
 
        /* ftp_mkd() calls failf() itself */
3591
 
        return result;
3592
 
      result = ftp_cwd(conn, path);
3593
 
    }
3594
 
    if(result)
3595
 
      failf(conn->data, "Couldn't CWD to %s", path);
3596
 
  }
3597
 
  return result;
3598
 
}
3599
 
 
3600
 
 
3601
 
 
3602
 
/***********************************************************************
3603
 
 *
3604
 
 * ftp_3rdparty_pretransfer()
3605
 
 *
3606
 
 * Preparation for 3rd party transfer.
3607
 
 *
3608
 
 */
3609
 
static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn)
3610
 
{
3611
 
  CURLcode result = CURLE_OK;
3612
 
  struct SessionHandle *data = conn->data;
3613
 
  struct connectdata *sec_conn = conn->sec_conn;
3614
 
 
3615
 
  conn->xfertype = TARGET3RD;
3616
 
  sec_conn->xfertype = SOURCE3RD;
3617
 
 
3618
 
  /* sets transfer type */
3619
 
  result = ftp_transfertype(conn, data->set.ftp_ascii);
3620
 
  if (result)
3621
 
    return result;
3622
 
 
3623
 
  result = ftp_transfertype(sec_conn, data->set.ftp_ascii);
3624
 
  if (result)
3625
 
    return result;
3626
 
 
3627
 
  /* Send any PREQUOTE strings after transfer type is set? */
3628
 
  if (data->set.source_prequote) {
3629
 
    /* sends command(s) to source server before file transfer */
3630
 
    result = ftp_sendquote(sec_conn, data->set.source_prequote);
3631
 
  }
3632
 
  if (!result && data->set.prequote)
3633
 
    result = ftp_sendquote(conn, data->set.prequote);
3634
 
 
3635
 
  return result;
3636
 
}
3637
 
 
3638
 
 
3639
 
 
3640
 
/***********************************************************************
3641
 
 *
3642
 
 * ftp_3rdparty_transfer()
3643
 
 *
3644
 
 * Performs 3rd party transfer.
3645
 
 *
3646
 
 */
3647
 
static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
3648
 
{
3649
 
  CURLcode result = CURLE_OK;
3650
 
  ssize_t nread;
3651
 
  int ftpcode, ip[4], port[2];
3652
 
  struct SessionHandle *data = conn->data;
3653
 
  struct connectdata *sec_conn = conn->sec_conn;
3654
 
  char *buf = data->state.buffer;   /* this is our buffer */
3655
 
  char *str = buf;
3656
 
  char pasv_port[50];
3657
 
  const char *stor_cmd;
3658
 
  struct connectdata *pasv_conn;
3659
 
  struct connectdata *port_conn;
3660
 
 
3661
 
  if (data->set.ftpport == NULL) {
3662
 
    pasv_conn = conn;
3663
 
    port_conn = sec_conn;
3664
 
  }
3665
 
  else {
3666
 
    pasv_conn = sec_conn;
3667
 
    port_conn = conn;
3668
 
  }
3669
 
 
3670
 
  result = ftp_cwd_and_create_path(conn);
3671
 
  if (result)
3672
 
    return result;
3673
 
 
3674
 
  /* sets the passive mode */
3675
 
  FTPSENDF(pasv_conn, "%s", "PASV");
3676
 
  result = Curl_GetFTPResponse(&nread, pasv_conn, &ftpcode);
3677
 
  if (result)
3678
 
    return result;
3679
 
 
3680
 
  if (ftpcode != 227) {
3681
 
    failf(data, "Odd return code after PASV: %03d", ftpcode);
3682
 
    return CURLE_FTP_WEIRD_PASV_REPLY;
3683
 
  }
3684
 
 
3685
 
  while (*str) {
3686
 
    if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
3687
 
                    &ip[0], &ip[1], &ip[2], &ip[3], &port[0], &port[1]))
3688
 
      break;
3689
 
    str++;
3690
 
  }
3691
 
 
3692
 
  if (!*str) {
3693
 
    failf(pasv_conn->data, "Couldn't interpret the 227-reply");
3694
 
    return CURLE_FTP_WEIRD_227_FORMAT;
3695
 
  }
3696
 
 
3697
 
  snprintf(pasv_port, sizeof(pasv_port), "%d,%d,%d,%d,%d,%d", ip[0], ip[1],
3698
 
           ip[2], ip[3], port[0], port[1]);
3699
 
 
3700
 
  /* sets data connection between remote hosts */
3701
 
  FTPSENDF(port_conn, "PORT %s", pasv_port);
3702
 
  result = Curl_GetFTPResponse(&nread, port_conn, &ftpcode);
3703
 
  if (result)
3704
 
    return result;
3705
 
 
3706
 
  if (ftpcode != 200) {
3707
 
    failf(data, "PORT command attempts failed: %03d", ftpcode);
3708
 
    return CURLE_FTP_PORT_FAILED;
3709
 
  }
3710
 
 
3711
 
  /* we might append onto the file instead of overwriting it */
3712
 
  stor_cmd = data->set.ftp_append?"APPE":"STOR";
3713
 
 
3714
 
  /* transfers file between remote hosts */
3715
 
  /* FIX: this should send a series of CWD commands and then RETR only the
3716
 
     ftp->file file. The conn->path "full path" is not unescaped. Test case
3717
 
     230 tests this. */
3718
 
  FTPSENDF(sec_conn, "RETR %s", sec_conn->path);
3719
 
 
3720
 
  if(!data->set.ftpport) {
3721
 
 
3722
 
    result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
3723
 
    if (result)
3724
 
      return result;
3725
 
 
3726
 
    if((ftpcode != 150) && (ftpcode != 125)) {
3727
 
      failf(data, "Failed RETR: %03d", ftpcode);
3728
 
      return CURLE_FTP_COULDNT_RETR_FILE;
3729
 
    }
3730
 
 
3731
 
    result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->proto.ftp->file);
3732
 
    if(CURLE_OK == result)
3733
 
      result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3734
 
    if (result)
3735
 
      return result;
3736
 
 
3737
 
    if (ftpcode >= 400) {
3738
 
      failf(data, "Failed FTP upload: %03d", ftpcode);
3739
 
      return CURLE_FTP_COULDNT_STOR_FILE;
3740
 
    }
3741
 
 
3742
 
  }
3743
 
  else {
3744
 
 
3745
 
    result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->proto.ftp->file);
3746
 
    if(CURLE_OK == result)
3747
 
      result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
3748
 
    if (result)
3749
 
      return result;
3750
 
 
3751
 
    if (ftpcode >= 400) {
3752
 
      failf(data, "Failed FTP upload: %03d", ftpcode);
3753
 
      return CURLE_FTP_COULDNT_STOR_FILE;
3754
 
    }
3755
 
 
3756
 
    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
3757
 
    if (result)
3758
 
      return result;
3759
 
 
3760
 
    if((ftpcode != 150) && (ftpcode != 125)) {
3761
 
      failf(data, "Failed FTP upload: %03d", ftpcode);
3762
 
      return CURLE_FTP_COULDNT_STOR_FILE;
3763
 
    }
3764
 
  }
3765
 
 
 
3624
      free(ftpc->entrypath);
 
3625
      ftpc->entrypath = NULL;
 
3626
    }
 
3627
    if(ftpc->cache) {
 
3628
      free(ftpc->cache);
 
3629
      ftpc->cache = NULL;
 
3630
    }
 
3631
    freedirs(conn);
 
3632
    if(ftpc->prevpath) {
 
3633
      free(ftpc->prevpath);
 
3634
      ftpc->prevpath = NULL;
 
3635
    }
 
3636
  }
3766
3637
  return CURLE_OK;
3767
3638
}
3768
3639
 
3776
3647
static
3777
3648
CURLcode ftp_parse_url_path(struct connectdata *conn)
3778
3649
{
3779
 
  CURLcode retcode = CURLE_OK;
3780
3650
  struct SessionHandle *data = conn->data;
3781
 
  struct FTP *ftp;
 
3651
  /* the ftp struct is already inited in ftp_connect() */
 
3652
  struct FTP *ftp = data->reqdata.proto.ftp;
 
3653
  struct ftp_conn *ftpc = &conn->proto.ftpc;
3782
3654
  size_t dlen;
3783
 
 
3784
3655
  char *slash_pos;  /* position of the first '/' char in curpos */
3785
 
  char *cur_pos = conn->path; /* current position in path. point at the begin
3786
 
                                 of next path component */
3787
 
 
3788
 
  /* the ftp struct is already inited in ftp_connect() */
3789
 
  ftp = conn->proto.ftp;
3790
 
  ftp->ctl_valid = FALSE;
3791
 
  ftp->cwdfail = FALSE;
 
3656
  char *path_to_use = data->reqdata.path;
 
3657
  char *cur_pos;
 
3658
 
 
3659
  cur_pos = path_to_use; /* current position in path. point at the begin
 
3660
                            of next path component */
 
3661
 
 
3662
  ftpc->ctl_valid = FALSE;
 
3663
  ftpc->cwdfail = FALSE;
3792
3664
 
3793
3665
  switch(data->set.ftp_filemethod) {
3794
3666
  case FTPFILE_NOCWD:
3795
3667
    /* fastest, but less standard-compliant */
3796
 
    ftp->file = conn->path;  /* this is a full file path */
 
3668
    ftp->file = data->reqdata.path;  /* this is a full file path */
3797
3669
    break;
3798
3670
 
3799
3671
  case FTPFILE_SINGLECWD:
3800
3672
    /* get the last slash */
3801
3673
    slash_pos=strrchr(cur_pos, '/');
3802
 
    if(slash_pos) {
3803
 
      ftp->dirdepth = 1; /* we consider it to be a single dir */
3804
 
      ftp->dirs = (char **)calloc(1, sizeof(ftp->dirs[0]));
3805
 
      if(!ftp->dirs)
 
3674
    if(slash_pos || !*cur_pos) {
 
3675
      ftpc->dirdepth = 1; /* we consider it to be a single dir */
 
3676
      ftpc->dirs = (char **)calloc(1, sizeof(ftpc->dirs[0]));
 
3677
      if(!ftpc->dirs)
3806
3678
        return CURLE_OUT_OF_MEMORY;
3807
3679
 
3808
 
      ftp->dirs[0] = curl_easy_unescape(conn->data, cur_pos,
3809
 
                                        (int)(slash_pos-cur_pos), NULL);
3810
 
      if(!ftp->dirs[0]) {
3811
 
        free(ftp->dirs);
 
3680
      ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
 
3681
                                         slash_pos?(int)(slash_pos-cur_pos):1,
 
3682
                                         NULL);
 
3683
      if(!ftpc->dirs[0]) {
 
3684
        free(ftpc->dirs);
3812
3685
        return CURLE_OUT_OF_MEMORY;
3813
3686
      }
3814
 
      ftp->file = slash_pos+1;  /* the rest is the file name */
 
3687
      ftp->file = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
3815
3688
    }
3816
3689
    else
3817
3690
      ftp->file = cur_pos;  /* this is a file name only */
3819
3692
 
3820
3693
  default: /* allow pretty much anything */
3821
3694
  case FTPFILE_MULTICWD:
3822
 
    ftp->dirdepth = 0;
3823
 
    ftp->diralloc = 5; /* default dir depth to allocate */
3824
 
    ftp->dirs = (char **)calloc(ftp->diralloc, sizeof(ftp->dirs[0]));
3825
 
    if(!ftp->dirs)
 
3695
    ftpc->dirdepth = 0;
 
3696
    ftpc->diralloc = 5; /* default dir depth to allocate */
 
3697
    ftpc->dirs = (char **)calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
 
3698
    if(!ftpc->dirs)
3826
3699
      return CURLE_OUT_OF_MEMORY;
3827
3700
 
3828
3701
    /* parse the URL path into separate path components */
3829
 
    while((slash_pos=strchr(cur_pos, '/'))) {
 
3702
    while ((slash_pos = strchr(cur_pos, '/')) != NULL) {
3830
3703
      /* 1 or 0 to indicate absolute directory */
3831
 
      bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0);
 
3704
      bool absolute_dir = (bool)((cur_pos - data->reqdata.path > 0) &&
 
3705
        (ftpc->dirdepth == 0));
3832
3706
 
3833
3707
      /* seek out the next path component */
3834
3708
      if (slash_pos-cur_pos) {
3835
 
        /* we skip empty path components, like "x//y" since the FTP command CWD
3836
 
           requires a parameter and a non-existant parameter a) doesn't work on
3837
 
           many servers and b) has no effect on the others. */
 
3709
        /* we skip empty path components, like "x//y" since the FTP command
 
3710
           CWD requires a parameter and a non-existant parameter a) doesn't
 
3711
           work on many servers and b) has no effect on the others. */
3838
3712
        int len = (int)(slash_pos - cur_pos + absolute_dir);
3839
 
        ftp->dirs[ftp->dirdepth] = curl_easy_unescape(conn->data,
3840
 
                                                      cur_pos - absolute_dir,
3841
 
                                                      len, NULL);
3842
 
        if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
 
3713
        ftpc->dirs[ftpc->dirdepth] = curl_easy_unescape(conn->data,
 
3714
                                                        cur_pos - absolute_dir,
 
3715
                                                        len, NULL);
 
3716
        if (!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
3843
3717
          failf(data, "no memory");
3844
 
          freedirs(ftp);
 
3718
          freedirs(conn);
3845
3719
          return CURLE_OUT_OF_MEMORY;
3846
3720
        }
3847
 
        if (isBadFtpString(ftp->dirs[ftp->dirdepth])) {
3848
 
          freedirs(ftp);
 
3721
        if (isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
 
3722
          free(ftpc->dirs[ftpc->dirdepth]);
 
3723
          freedirs(conn);
3849
3724
          return CURLE_URL_MALFORMAT;
3850
3725
        }
3851
3726
      }
3854
3729
        continue;
3855
3730
      }
3856
3731
 
3857
 
      if(!retcode) {
3858
 
        cur_pos = slash_pos + 1; /* jump to the rest of the string */
3859
 
        if(++ftp->dirdepth >= ftp->diralloc) {
3860
 
          /* enlarge array */
3861
 
          char *bigger;
3862
 
          ftp->diralloc *= 2; /* double the size each time */
3863
 
          bigger = realloc(ftp->dirs, ftp->diralloc * sizeof(ftp->dirs[0]));
3864
 
          if(!bigger) {
3865
 
            ftp->dirdepth--;
3866
 
            freedirs(ftp);
3867
 
            return CURLE_OUT_OF_MEMORY;
3868
 
          }
3869
 
          ftp->dirs = (char **)bigger;
3870
 
        }
 
3732
      cur_pos = slash_pos + 1; /* jump to the rest of the string */
 
3733
      if(++ftpc->dirdepth >= ftpc->diralloc) {
 
3734
        /* enlarge array */
 
3735
        char *bigger;
 
3736
        ftpc->diralloc *= 2; /* double the size each time */
 
3737
        bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
 
3738
        if(!bigger) {
 
3739
          freedirs(conn);
 
3740
          return CURLE_OUT_OF_MEMORY;
 
3741
        }
 
3742
        ftpc->dirs = (char **)bigger;
3871
3743
      }
3872
3744
    }
3873
3745
 
3877
3749
  if(*ftp->file) {
3878
3750
    ftp->file = curl_easy_unescape(conn->data, ftp->file, 0, NULL);
3879
3751
    if(NULL == ftp->file) {
3880
 
      freedirs(ftp);
 
3752
      freedirs(conn);
3881
3753
      failf(data, "no memory");
3882
3754
      return CURLE_OUT_OF_MEMORY;
3883
3755
    }
3884
3756
    if (isBadFtpString(ftp->file)) {
3885
 
      freedirs(ftp);
 
3757
      freedirs(conn);
3886
3758
      return CURLE_URL_MALFORMAT;
3887
3759
    }
3888
3760
  }
3897
3769
    return CURLE_URL_MALFORMAT;
3898
3770
  }
3899
3771
 
3900
 
  ftp->cwddone = FALSE; /* default to not done */
 
3772
  ftpc->cwddone = FALSE; /* default to not done */
3901
3773
 
3902
 
  if(ftp->prevpath) {
 
3774
  if(ftpc->prevpath) {
3903
3775
    /* prevpath is "raw" so we convert the input path before we compare the
3904
3776
       strings */
3905
 
    char *path = curl_easy_unescape(conn->data, conn->path, 0, NULL);
 
3777
    char *path = curl_easy_unescape(conn->data, data->reqdata.path, 0, NULL);
3906
3778
    if(!path)
3907
3779
      return CURLE_OUT_OF_MEMORY;
3908
3780
 
3909
3781
    dlen = strlen(path) - (ftp->file?strlen(ftp->file):0);
3910
 
    if((dlen == strlen(ftp->prevpath)) &&
3911
 
       curl_strnequal(path, ftp->prevpath, dlen)) {
 
3782
    if((dlen == strlen(ftpc->prevpath)) &&
 
3783
       curl_strnequal(path, ftpc->prevpath, dlen)) {
3912
3784
      infof(data, "Request has same path as previous transfer\n");
3913
 
      ftp->cwddone = TRUE;
 
3785
      ftpc->cwddone = TRUE;
3914
3786
    }
3915
3787
    free(path);
3916
3788
  }
3917
3789
 
3918
 
  return retcode;
3919
 
}
3920
 
 
3921
 
 
3922
 
 
3923
 
/***********************************************************************
3924
 
 *
3925
 
 * ftp_cwd_and_create_path()
3926
 
 *
3927
 
 * Creates full path on remote target host.
3928
 
 *
3929
 
 */
3930
 
static
3931
 
CURLcode ftp_cwd_and_create_path(struct connectdata *conn)
3932
 
{
3933
 
  CURLcode result = CURLE_OK;
3934
 
  /* the ftp struct is already inited in Curl_ftp_connect() */
3935
 
  struct FTP *ftp = conn->proto.ftp;
3936
 
  int i;
3937
 
 
3938
 
  if(ftp->cwddone)
3939
 
    /* already done and fine */
3940
 
    return CURLE_OK;
3941
 
 
3942
 
  /* This is a re-used connection. Since we change directory to where the
3943
 
     transfer is taking place, we must now get back to the original dir
3944
 
     where we ended up after login: */
3945
 
  if (conn->bits.reuse && ftp->entrypath) {
3946
 
    if ((result = ftp_cwd_and_mkd(conn, ftp->entrypath)) != CURLE_OK)
3947
 
      return result;
3948
 
  }
3949
 
 
3950
 
  for (i=0; i < ftp->dirdepth; i++) {
3951
 
    /* RFC 1738 says empty components should be respected too, but
3952
 
       that is plain stupid since CWD can't be used with an empty argument */
3953
 
    if ((result = ftp_cwd_and_mkd(conn, ftp->dirs[i])) != CURLE_OK)
3954
 
      return result;
3955
 
  }
3956
 
 
3957
 
  return result;
 
3790
  return CURLE_OK;
3958
3791
}
3959
3792
 
3960
3793
/* call this when the DO phase has completed */
3962
3795
                                 bool connected)
3963
3796
{
3964
3797
  CURLcode result = CURLE_OK;
3965
 
  struct FTP *ftp = conn->proto.ftp;
 
3798
  struct FTP *ftp = conn->data->reqdata.proto.ftp;
 
3799
  struct ftp_conn *ftpc = &conn->proto.ftpc;
3966
3800
 
3967
3801
  if(connected)
3968
3802
    result = Curl_ftp_nextconnect(conn);
3976
3810
 
3977
3811
  if(ftp->no_transfer)
3978
3812
    /* no data to transfer */
3979
 
    result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
 
3813
    result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
3980
3814
  else if(!connected)
3981
3815
    /* since we didn't connect now, we want do_more to get called */
3982
3816
    conn->bits.do_more = TRUE;
3983
3817
 
3984
 
  ftp->ctl_valid = TRUE; /* seems good */
 
3818
  ftpc->ctl_valid = TRUE; /* seems good */
3985
3819
 
3986
3820
  return result;
3987
3821
}
4020
3854
  CURLcode result=CURLE_OK;
4021
3855
  bool connected=0;
4022
3856
  struct SessionHandle *data = conn->data;
4023
 
  struct FTP *ftp;
4024
 
 
4025
 
  /* the ftp struct is already inited in ftp_connect() */
4026
 
  ftp = conn->proto.ftp;
4027
 
  conn->size = -1; /* make sure this is unknown at this point */
 
3857
  struct ftp_conn *ftpc = &conn->proto.ftpc;
 
3858
  data->reqdata.size = -1; /* make sure this is unknown at this point */
4028
3859
 
4029
3860
  Curl_pgrsSetUploadCounter(data, 0);
4030
3861
  Curl_pgrsSetDownloadCounter(data, 0);
4031
3862
  Curl_pgrsSetUploadSize(data, 0);
4032
3863
  Curl_pgrsSetDownloadSize(data, 0);
4033
3864
 
4034
 
  ftp->ctl_valid = TRUE; /* starts good */
 
3865
  ftpc->ctl_valid = TRUE; /* starts good */
4035
3866
 
4036
3867
  result = ftp_perform(conn,
4037
3868
                       &connected, /* have we connected after PASV/PORT */
4048
3879
      return result;
4049
3880
  }
4050
3881
  else
4051
 
    freedirs(ftp);
4052
 
 
4053
 
  return result;
4054
 
}
4055
 
 
4056
 
 
4057
 
 
4058
 
/***********************************************************************
4059
 
 *
4060
 
 * ftp_3rdparty()
4061
 
 *
4062
 
 * The input argument is already checked for validity.
4063
 
 * Performs a 3rd party transfer between two remote hosts.
4064
 
 */
4065
 
static CURLcode ftp_3rdparty(struct connectdata *conn)
4066
 
{
4067
 
  CURLcode result = CURLE_OK;
4068
 
 
4069
 
  conn->proto.ftp->ctl_valid = conn->sec_conn->proto.ftp->ctl_valid = TRUE;
4070
 
  conn->size = conn->sec_conn->size = -1;
4071
 
 
4072
 
  result = ftp_3rdparty_pretransfer(conn);
4073
 
  if (!result)
4074
 
    result = ftp_3rdparty_transfer(conn);
 
3882
    freedirs(conn);
4075
3883
 
4076
3884
  return result;
4077
3885
}