source: trunk/essentials/net-misc/wget/src/ftp.c

Last change on this file was 3440, checked in by bird, 18 years ago

wget 1.10.2

File size: 52.6 KB
Line 
1/* File Transfer Protocol support.
2 Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001
3 Free Software Foundation, Inc.
4
5This file is part of GNU Wget.
6
7GNU Wget is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12GNU Wget is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with Wget; if not, write to the Free Software
19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21In addition, as a special exception, the Free Software Foundation
22gives permission to link the code of its release of Wget with the
23OpenSSL project's "OpenSSL" library (or with modified versions of it
24that use the same license as the "OpenSSL" library), and distribute
25the linked executables. You must obey the GNU General Public License
26in all respects for all of the code used other than "OpenSSL". If you
27modify this file, you may extend this exception to your version of the
28file, but you are not obligated to do so. If you do not wish to do
29so, delete this exception statement from your version. */
30
31#include <config.h>
32
33#include <stdio.h>
34#include <stdlib.h>
35#ifdef HAVE_STRING_H
36# include <string.h>
37#else
38# include <strings.h>
39#endif
40#ifdef HAVE_UNISTD_H
41# include <unistd.h>
42#endif
43#include <sys/types.h>
44#include <assert.h>
45#include <errno.h>
46
47#include "wget.h"
48#include "utils.h"
49#include "url.h"
50#include "retr.h"
51#include "ftp.h"
52#include "connect.h"
53#include "host.h"
54#include "netrc.h"
55#include "convert.h" /* for downloaded_file */
56#include "recur.h" /* for INFINITE_RECURSION */
57
58#ifndef errno
59extern int errno;
60#endif
61
62extern SUM_SIZE_INT total_downloaded_bytes;
63
64/* File where the "ls -al" listing will be saved. */
65#define LIST_FILENAME ".listing"
66
67extern char ftp_last_respline[];
68
69extern FILE *output_stream;
70extern int output_stream_regular;
71
72typedef struct
73{
74 int st; /* connection status */
75 int cmd; /* command code */
76 int csock; /* control connection socket */
77 double dltime; /* time of the download in msecs */
78 enum stype rs; /* remote system reported by ftp server */
79 char *id; /* initial directory */
80 char *target; /* target file name */
81 struct url *proxy; /* FTWK-style proxy */
82} ccon;
83
84
85/* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in
86 the string S, and return the number converted to wgint, if found, 0
87 otherwise. */
88static wgint
89ftp_expected_bytes (const char *s)
90{
91 wgint res;
92
93 while (1)
94 {
95 while (*s && *s != '(')
96 ++s;
97 if (!*s)
98 return 0;
99 ++s; /* skip the '(' */
100 res = str_to_wgint (s, (char **) &s, 10);
101 if (!*s)
102 return 0;
103 while (*s && ISSPACE (*s))
104 ++s;
105 if (!*s)
106 return 0;
107 if (TOLOWER (*s) != 'b')
108 continue;
109 if (strncasecmp (s, "byte", 4))
110 continue;
111 else
112 break;
113 }
114 return res;
115}
116
117#ifdef ENABLE_IPV6
118/*
119 * This function sets up a passive data connection with the FTP server.
120 * It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv.
121 */
122static uerr_t
123ftp_do_pasv (int csock, ip_address *addr, int *port)
124{
125 uerr_t err;
126
127 /* We need to determine the address family and need to call
128 getpeername, so while we're at it, store the address to ADDR.
129 ftp_pasv and ftp_lpsv can simply override it. */
130 if (!socket_ip_address (csock, addr, ENDPOINT_PEER))
131 abort ();
132
133 /* If our control connection is over IPv6, then we first try EPSV and then
134 * LPSV if the former is not supported. If the control connection is over
135 * IPv4, we simply issue the good old PASV request. */
136 switch (addr->type)
137 {
138 case IPV4_ADDRESS:
139 if (!opt.server_response)
140 logputs (LOG_VERBOSE, "==> PASV ... ");
141 err = ftp_pasv (csock, addr, port);
142 break;
143 case IPV6_ADDRESS:
144 if (!opt.server_response)
145 logputs (LOG_VERBOSE, "==> EPSV ... ");
146 err = ftp_epsv (csock, addr, port);
147
148 /* If EPSV is not supported try LPSV */
149 if (err == FTPNOPASV)
150 {
151 if (!opt.server_response)
152 logputs (LOG_VERBOSE, "==> LPSV ... ");
153 err = ftp_lpsv (csock, addr, port);
154 }
155 break;
156 default:
157 abort ();
158 }
159
160 return err;
161}
162
163/*
164 * This function sets up an active data connection with the FTP server.
165 * It is merely a wrapper around ftp_eprt, ftp_lprt and ftp_port.
166 */
167static uerr_t
168ftp_do_port (int csock, int *local_sock)
169{
170 uerr_t err;
171 ip_address cip;
172
173 if (!socket_ip_address (csock, &cip, ENDPOINT_PEER))
174 abort ();
175
176 /* If our control connection is over IPv6, then we first try EPRT and then
177 * LPRT if the former is not supported. If the control connection is over
178 * IPv4, we simply issue the good old PORT request. */
179 switch (cip.type)
180 {
181 case IPV4_ADDRESS:
182 if (!opt.server_response)
183 logputs (LOG_VERBOSE, "==> PORT ... ");
184 err = ftp_port (csock, local_sock);
185 break;
186 case IPV6_ADDRESS:
187 if (!opt.server_response)
188 logputs (LOG_VERBOSE, "==> EPRT ... ");
189 err = ftp_eprt (csock, local_sock);
190
191 /* If EPRT is not supported try LPRT */
192 if (err == FTPPORTERR)
193 {
194 if (!opt.server_response)
195 logputs (LOG_VERBOSE, "==> LPRT ... ");
196 err = ftp_lprt (csock, local_sock);
197 }
198 break;
199 default:
200 abort ();
201 }
202 return err;
203}
204#else
205
206static uerr_t
207ftp_do_pasv (int csock, ip_address *addr, int *port)
208{
209 if (!opt.server_response)
210 logputs (LOG_VERBOSE, "==> PASV ... ");
211 return ftp_pasv (csock, addr, port);
212}
213
214static uerr_t
215ftp_do_port (int csock, int *local_sock)
216{
217 if (!opt.server_response)
218 logputs (LOG_VERBOSE, "==> PORT ... ");
219 return ftp_port (csock, local_sock);
220}
221#endif
222
223static void
224print_length (wgint size, wgint start, int authoritative)
225{
226 logprintf (LOG_VERBOSE, _("Length: %s"), with_thousand_seps (size));
227 if (size >= 1024)
228 logprintf (LOG_VERBOSE, " (%s)", human_readable (size));
229 if (start > 0)
230 {
231 if (start >= 1024)
232 logprintf (LOG_VERBOSE, _(", %s (%s) remaining"),
233 with_thousand_seps (size - start),
234 human_readable (size - start));
235 else
236 logprintf (LOG_VERBOSE, _(", %s remaining"),
237 with_thousand_seps (size - start));
238 }
239 logputs (LOG_VERBOSE, !authoritative ? _(" (unauthoritative)\n") : "\n");
240}
241
242/* Retrieves a file with denoted parameters through opening an FTP
243 connection to the server. It always closes the data connection,
244 and closes the control connection in case of error. */
245static uerr_t
246getftp (struct url *u, wgint *len, wgint restval, ccon *con)
247{
248 int csock, dtsock, local_sock, res;
249 uerr_t err = RETROK; /* appease the compiler */
250 FILE *fp;
251 char *user, *passwd, *respline;
252 char *tms, *tmrate;
253 int cmd = con->cmd;
254 int pasv_mode_open = 0;
255 wgint expected_bytes = 0;
256 int rest_failed = 0;
257 int flags;
258 wgint rd_size;
259
260 assert (con != NULL);
261 assert (con->target != NULL);
262
263 /* Debug-check of the sanity of the request by making sure that LIST
264 and RETR are never both requested (since we can handle only one
265 at a time. */
266 assert (!((cmd & DO_LIST) && (cmd & DO_RETR)));
267 /* Make sure that at least *something* is requested. */
268 assert ((cmd & (DO_LIST | DO_CWD | DO_RETR | DO_LOGIN)) != 0);
269
270 user = u->user;
271 passwd = u->passwd;
272 search_netrc (u->host, (const char **)&user, (const char **)&passwd, 1);
273 user = user ? user : (opt.ftp_user ? opt.ftp_user : opt.user);
274 if (!user) user = "anonymous";
275 passwd = passwd ? passwd : (opt.ftp_passwd ? opt.ftp_passwd : opt.passwd);
276 if (!passwd) passwd = "-wget@";
277
278 dtsock = -1;
279 local_sock = -1;
280 con->dltime = 0;
281
282 if (!(cmd & DO_LOGIN))
283 csock = con->csock;
284 else /* cmd & DO_LOGIN */
285 {
286 char type_char;
287 char *host = con->proxy ? con->proxy->host : u->host;
288 int port = con->proxy ? con->proxy->port : u->port;
289 char *logname = user;
290
291 if (con->proxy)
292 {
293 /* If proxy is in use, log in as username@target-site. */
294 logname = concat_strings (user, "@", u->host, (char *) 0);
295 }
296
297 /* Login to the server: */
298
299 /* First: Establish the control connection. */
300
301 csock = connect_to_host (host, port);
302 if (csock == E_HOST)
303 return HOSTERR;
304 else if (csock < 0)
305 return (retryable_socket_connect_error (errno)
306 ? CONERROR : CONIMPOSSIBLE);
307
308 if (cmd & LEAVE_PENDING)
309 con->csock = csock;
310 else
311 con->csock = -1;
312
313 /* Second: Login with proper USER/PASS sequence. */
314 logprintf (LOG_VERBOSE, _("Logging in as %s ... "), escnonprint (user));
315 if (opt.server_response)
316 logputs (LOG_ALWAYS, "\n");
317 err = ftp_login (csock, logname, passwd);
318
319 if (con->proxy)
320 xfree (logname);
321
322 /* FTPRERR, FTPSRVERR, WRITEFAILED, FTPLOGREFUSED, FTPLOGINC */
323 switch (err)
324 {
325 case FTPRERR:
326 logputs (LOG_VERBOSE, "\n");
327 logputs (LOG_NOTQUIET, _("\
328Error in server response, closing control connection.\n"));
329 fd_close (csock);
330 con->csock = -1;
331 return err;
332 case FTPSRVERR:
333 logputs (LOG_VERBOSE, "\n");
334 logputs (LOG_NOTQUIET, _("Error in server greeting.\n"));
335 fd_close (csock);
336 con->csock = -1;
337 return err;
338 case WRITEFAILED:
339 logputs (LOG_VERBOSE, "\n");
340 logputs (LOG_NOTQUIET,
341 _("Write failed, closing control connection.\n"));
342 fd_close (csock);
343 con->csock = -1;
344 return err;
345 case FTPLOGREFUSED:
346 logputs (LOG_VERBOSE, "\n");
347 logputs (LOG_NOTQUIET, _("The server refuses login.\n"));
348 fd_close (csock);
349 con->csock = -1;
350 return FTPLOGREFUSED;
351 case FTPLOGINC:
352 logputs (LOG_VERBOSE, "\n");
353 logputs (LOG_NOTQUIET, _("Login incorrect.\n"));
354 fd_close (csock);
355 con->csock = -1;
356 return FTPLOGINC;
357 case FTPOK:
358 if (!opt.server_response)
359 logputs (LOG_VERBOSE, _("Logged in!\n"));
360 break;
361 default:
362 abort ();
363 }
364 /* Third: Get the system type */
365 if (!opt.server_response)
366 logprintf (LOG_VERBOSE, "==> SYST ... ");
367 err = ftp_syst (csock, &con->rs);
368 /* FTPRERR */
369 switch (err)
370 {
371 case FTPRERR:
372 logputs (LOG_VERBOSE, "\n");
373 logputs (LOG_NOTQUIET, _("\
374Error in server response, closing control connection.\n"));
375 fd_close (csock);
376 con->csock = -1;
377 return err;
378 case FTPSRVERR:
379 logputs (LOG_VERBOSE, "\n");
380 logputs (LOG_NOTQUIET,
381 _("Server error, can't determine system type.\n"));
382 break;
383 case FTPOK:
384 /* Everything is OK. */
385 break;
386 default:
387 abort ();
388 }
389 if (!opt.server_response && err != FTPSRVERR)
390 logputs (LOG_VERBOSE, _("done. "));
391
392 /* Fourth: Find the initial ftp directory */
393
394 if (!opt.server_response)
395 logprintf (LOG_VERBOSE, "==> PWD ... ");
396 err = ftp_pwd (csock, &con->id);
397 /* FTPRERR */
398 switch (err)
399 {
400 case FTPRERR:
401 logputs (LOG_VERBOSE, "\n");
402 logputs (LOG_NOTQUIET, _("\
403Error in server response, closing control connection.\n"));
404 fd_close (csock);
405 con->csock = -1;
406 return err;
407 case FTPSRVERR :
408 /* PWD unsupported -- assume "/". */
409 xfree_null (con->id);
410 con->id = xstrdup ("/");
411 break;
412 case FTPOK:
413 /* Everything is OK. */
414 break;
415 default:
416 abort ();
417 }
418 /* VMS will report something like "PUB$DEVICE:[INITIAL.FOLDER]".
419 Convert it to "/INITIAL/FOLDER" */
420 if (con->rs == ST_VMS)
421 {
422 char *path = strchr (con->id, '[');
423 char *pathend = path ? strchr (path + 1, ']') : NULL;
424 if (!path || !pathend)
425 DEBUGP (("Initial VMS directory not in the form [...]!\n"));
426 else
427 {
428 char *idir = con->id;
429 DEBUGP (("Preprocessing the initial VMS directory\n"));
430 DEBUGP ((" old = '%s'\n", con->id));
431 /* We do the conversion in-place by copying the stuff
432 between [ and ] to the beginning, and changing dots
433 to slashes at the same time. */
434 *idir++ = '/';
435 for (++path; path < pathend; path++, idir++)
436 *idir = *path == '.' ? '/' : *path;
437 *idir = '\0';
438 DEBUGP ((" new = '%s'\n\n", con->id));
439 }
440 }
441 if (!opt.server_response)
442 logputs (LOG_VERBOSE, _("done.\n"));
443
444 /* Fifth: Set the FTP type. */
445 type_char = ftp_process_type (u->params);
446 if (!opt.server_response)
447 logprintf (LOG_VERBOSE, "==> TYPE %c ... ", type_char);
448 err = ftp_type (csock, type_char);
449 /* FTPRERR, WRITEFAILED, FTPUNKNOWNTYPE */
450 switch (err)
451 {
452 case FTPRERR:
453 logputs (LOG_VERBOSE, "\n");
454 logputs (LOG_NOTQUIET, _("\
455Error in server response, closing control connection.\n"));
456 fd_close (csock);
457 con->csock = -1;
458 return err;
459 case WRITEFAILED:
460 logputs (LOG_VERBOSE, "\n");
461 logputs (LOG_NOTQUIET,
462 _("Write failed, closing control connection.\n"));
463 fd_close (csock);
464 con->csock = -1;
465 return err;
466 case FTPUNKNOWNTYPE:
467 logputs (LOG_VERBOSE, "\n");
468 logprintf (LOG_NOTQUIET,
469 _("Unknown type `%c', closing control connection.\n"),
470 type_char);
471 fd_close (csock);
472 con->csock = -1;
473 return err;
474 case FTPOK:
475 /* Everything is OK. */
476 break;
477 default:
478 abort ();
479 }
480 if (!opt.server_response)
481 logputs (LOG_VERBOSE, _("done. "));
482 } /* do login */
483
484 if (cmd & DO_CWD)
485 {
486 if (!*u->dir)
487 logputs (LOG_VERBOSE, _("==> CWD not needed.\n"));
488 else
489 {
490 char *target = u->dir;
491
492 DEBUGP (("changing working directory\n"));
493
494 /* Change working directory. To change to a non-absolute
495 Unix directory, we need to prepend initial directory
496 (con->id) to it. Absolute directories "just work".
497
498 A relative directory is one that does not begin with '/'
499 and, on non-Unix OS'es, one that doesn't begin with
500 "[a-z]:".
501
502 This is not done for OS400, which doesn't use
503 "/"-delimited directories, nor does it support directory
504 hierarchies. "CWD foo" followed by "CWD bar" leaves us
505 in "bar", not in "foo/bar", as would be customary
506 elsewhere. */
507
508 if (target[0] != '/'
509 && !(con->rs != ST_UNIX
510 && ISALPHA (target[0])
511 && target[1] == ':')
512 && con->rs != ST_OS400)
513 {
514 int idlen = strlen (con->id);
515 char *ntarget, *p;
516
517 /* Strip trailing slash(es) from con->id. */
518 while (idlen > 0 && con->id[idlen - 1] == '/')
519 --idlen;
520 p = ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1);
521 memcpy (p, con->id, idlen);
522 p += idlen;
523 *p++ = '/';
524 strcpy (p, target);
525
526 DEBUGP (("Prepended initial PWD to relative path:\n"));
527 DEBUGP ((" pwd: '%s'\n old: '%s'\n new: '%s'\n",
528 con->id, target, ntarget));
529 target = ntarget;
530 }
531
532 /* If the FTP host runs VMS, we will have to convert the absolute
533 directory path in UNIX notation to absolute directory path in
534 VMS notation as VMS FTP servers do not like UNIX notation of
535 absolute paths. "VMS notation" is [dir.subdir.subsubdir]. */
536
537 if (con->rs == ST_VMS)
538 {
539 char *tmpp;
540 char *ntarget = (char *)alloca (strlen (target) + 2);
541 /* We use a converted initial dir, so directories in
542 TARGET will be separated with slashes, something like
543 "/INITIAL/FOLDER/DIR/SUBDIR". Convert that to
544 "[INITIAL.FOLDER.DIR.SUBDIR]". */
545 strcpy (ntarget, target);
546 assert (*ntarget == '/');
547 *ntarget = '[';
548 for (tmpp = ntarget + 1; *tmpp; tmpp++)
549 if (*tmpp == '/')
550 *tmpp = '.';
551 *tmpp++ = ']';
552 *tmpp = '\0';
553 DEBUGP (("Changed file name to VMS syntax:\n"));
554 DEBUGP ((" Unix: '%s'\n VMS: '%s'\n", target, ntarget));
555 target = ntarget;
556 }
557
558 if (!opt.server_response)
559 logprintf (LOG_VERBOSE, "==> CWD %s ... ", escnonprint (target));
560 err = ftp_cwd (csock, target);
561 /* FTPRERR, WRITEFAILED, FTPNSFOD */
562 switch (err)
563 {
564 case FTPRERR:
565 logputs (LOG_VERBOSE, "\n");
566 logputs (LOG_NOTQUIET, _("\
567Error in server response, closing control connection.\n"));
568 fd_close (csock);
569 con->csock = -1;
570 return err;
571 case WRITEFAILED:
572 logputs (LOG_VERBOSE, "\n");
573 logputs (LOG_NOTQUIET,
574 _("Write failed, closing control connection.\n"));
575 fd_close (csock);
576 con->csock = -1;
577 return err;
578 case FTPNSFOD:
579 logputs (LOG_VERBOSE, "\n");
580 logprintf (LOG_NOTQUIET, _("No such directory `%s'.\n\n"),
581 escnonprint (u->dir));
582 fd_close (csock);
583 con->csock = -1;
584 return err;
585 case FTPOK:
586 break;
587 default:
588 abort ();
589 }
590 if (!opt.server_response)
591 logputs (LOG_VERBOSE, _("done.\n"));
592 }
593 }
594 else /* do not CWD */
595 logputs (LOG_VERBOSE, _("==> CWD not required.\n"));
596
597 if ((cmd & DO_RETR) && restval && *len == 0)
598 {
599 if (opt.verbose)
600 {
601 if (!opt.server_response)
602 logprintf (LOG_VERBOSE, "==> SIZE %s ... ", escnonprint (u->file));
603 }
604
605 err = ftp_size (csock, u->file, len);
606 /* FTPRERR */
607 switch (err)
608 {
609 case FTPRERR:
610 case FTPSRVERR :
611 logputs (LOG_VERBOSE, "\n");
612 logputs (LOG_NOTQUIET, _("\
613Error in server response, closing control connection.\n"));
614 fd_close (csock);
615 con->csock = -1;
616 return err;
617 case FTPOK:
618 /* Everything is OK. */
619 break;
620 default:
621 abort ();
622 }
623 if (!opt.server_response)
624 logputs (LOG_VERBOSE, _("done.\n"));
625 }
626
627 /* If anything is to be retrieved, PORT (or PASV) must be sent. */
628 if (cmd & (DO_LIST | DO_RETR))
629 {
630 if (opt.ftp_pasv > 0)
631 {
632 ip_address passive_addr;
633 int passive_port;
634 err = ftp_do_pasv (csock, &passive_addr, &passive_port);
635 /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */
636 switch (err)
637 {
638 case FTPRERR:
639 logputs (LOG_VERBOSE, "\n");
640 logputs (LOG_NOTQUIET, _("\
641Error in server response, closing control connection.\n"));
642 fd_close (csock);
643 con->csock = -1;
644 return err;
645 case WRITEFAILED:
646 logputs (LOG_VERBOSE, "\n");
647 logputs (LOG_NOTQUIET,
648 _("Write failed, closing control connection.\n"));
649 fd_close (csock);
650 con->csock = -1;
651 return err;
652 case FTPNOPASV:
653 logputs (LOG_VERBOSE, "\n");
654 logputs (LOG_NOTQUIET, _("Cannot initiate PASV transfer.\n"));
655 break;
656 case FTPINVPASV:
657 logputs (LOG_VERBOSE, "\n");
658 logputs (LOG_NOTQUIET, _("Cannot parse PASV response.\n"));
659 break;
660 case FTPOK:
661 break;
662 default:
663 abort ();
664 } /* switch (err) */
665 if (err==FTPOK)
666 {
667 DEBUGP (("trying to connect to %s port %d\n",
668 pretty_print_address (&passive_addr),
669 passive_port));
670 dtsock = connect_to_ip (&passive_addr, passive_port, NULL);
671 if (dtsock < 0)
672 {
673 int save_errno = errno;
674 fd_close (csock);
675 con->csock = -1;
676 logprintf (LOG_VERBOSE, _("couldn't connect to %s port %d: %s\n"),
677 pretty_print_address (&passive_addr), passive_port,
678 strerror (save_errno));
679 return (retryable_socket_connect_error (save_errno)
680 ? CONERROR : CONIMPOSSIBLE);
681 }
682
683 pasv_mode_open = 1; /* Flag to avoid accept port */
684 if (!opt.server_response)
685 logputs (LOG_VERBOSE, _("done. "));
686 } /* err==FTP_OK */
687 }
688
689 if (!pasv_mode_open) /* Try to use a port command if PASV failed */
690 {
691 err = ftp_do_port (csock, &local_sock);
692 /* FTPRERR, WRITEFAILED, bindport (FTPSYSERR), HOSTERR,
693 FTPPORTERR */
694 switch (err)
695 {
696 case FTPRERR:
697 logputs (LOG_VERBOSE, "\n");
698 logputs (LOG_NOTQUIET, _("\
699Error in server response, closing control connection.\n"));
700 fd_close (csock);
701 con->csock = -1;
702 fd_close (dtsock);
703 fd_close (local_sock);
704 return err;
705 case WRITEFAILED:
706 logputs (LOG_VERBOSE, "\n");
707 logputs (LOG_NOTQUIET,
708 _("Write failed, closing control connection.\n"));
709 fd_close (csock);
710 con->csock = -1;
711 fd_close (dtsock);
712 fd_close (local_sock);
713 return err;
714 case CONSOCKERR:
715 logputs (LOG_VERBOSE, "\n");
716 logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
717 fd_close (csock);
718 con->csock = -1;
719 fd_close (dtsock);
720 fd_close (local_sock);
721 return err;
722 case FTPSYSERR:
723 logputs (LOG_VERBOSE, "\n");
724 logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"),
725 strerror (errno));
726 fd_close (dtsock);
727 return err;
728 case FTPPORTERR:
729 logputs (LOG_VERBOSE, "\n");
730 logputs (LOG_NOTQUIET, _("Invalid PORT.\n"));
731 fd_close (csock);
732 con->csock = -1;
733 fd_close (dtsock);
734 fd_close (local_sock);
735 return err;
736 case FTPOK:
737 break;
738 default:
739 abort ();
740 } /* port switch */
741 if (!opt.server_response)
742 logputs (LOG_VERBOSE, _("done. "));
743 } /* dtsock == -1 */
744 } /* cmd & (DO_LIST | DO_RETR) */
745
746 /* Restart if needed. */
747 if (restval && (cmd & DO_RETR))
748 {
749 if (!opt.server_response)
750 logprintf (LOG_VERBOSE, "==> REST %s ... ",
751 number_to_static_string (restval));
752 err = ftp_rest (csock, restval);
753
754 /* FTPRERR, WRITEFAILED, FTPRESTFAIL */
755 switch (err)
756 {
757 case FTPRERR:
758 logputs (LOG_VERBOSE, "\n");
759 logputs (LOG_NOTQUIET, _("\
760Error in server response, closing control connection.\n"));
761 fd_close (csock);
762 con->csock = -1;
763 fd_close (dtsock);
764 fd_close (local_sock);
765 return err;
766 case WRITEFAILED:
767 logputs (LOG_VERBOSE, "\n");
768 logputs (LOG_NOTQUIET,
769 _("Write failed, closing control connection.\n"));
770 fd_close (csock);
771 con->csock = -1;
772 fd_close (dtsock);
773 fd_close (local_sock);
774 return err;
775 case FTPRESTFAIL:
776 logputs (LOG_VERBOSE, _("\nREST failed, starting from scratch.\n"));
777 rest_failed = 1;
778 break;
779 case FTPOK:
780 break;
781 default:
782 abort ();
783 }
784 if (err != FTPRESTFAIL && !opt.server_response)
785 logputs (LOG_VERBOSE, _("done. "));
786 } /* restval && cmd & DO_RETR */
787
788 if (cmd & DO_RETR)
789 {
790 /* If we're in spider mode, don't really retrieve anything. The
791 fact that we got to this point should be proof enough that
792 the file exists, vaguely akin to HTTP's concept of a "HEAD"
793 request. */
794 if (opt.spider)
795 {
796 fd_close (csock);
797 con->csock = -1;
798 fd_close (dtsock);
799 fd_close (local_sock);
800 return RETRFINISHED;
801 }
802
803 if (opt.verbose)
804 {
805 if (!opt.server_response)
806 {
807 if (restval)
808 logputs (LOG_VERBOSE, "\n");
809 logprintf (LOG_VERBOSE, "==> RETR %s ... ", escnonprint (u->file));
810 }
811 }
812
813 err = ftp_retr (csock, u->file);
814 /* FTPRERR, WRITEFAILED, FTPNSFOD */
815 switch (err)
816 {
817 case FTPRERR:
818 logputs (LOG_VERBOSE, "\n");
819 logputs (LOG_NOTQUIET, _("\
820Error in server response, closing control connection.\n"));
821 fd_close (csock);
822 con->csock = -1;
823 fd_close (dtsock);
824 fd_close (local_sock);
825 return err;
826 case WRITEFAILED:
827 logputs (LOG_VERBOSE, "\n");
828 logputs (LOG_NOTQUIET,
829 _("Write failed, closing control connection.\n"));
830 fd_close (csock);
831 con->csock = -1;
832 fd_close (dtsock);
833 fd_close (local_sock);
834 return err;
835 case FTPNSFOD:
836 logputs (LOG_VERBOSE, "\n");
837 logprintf (LOG_NOTQUIET, _("No such file `%s'.\n\n"),
838 escnonprint (u->file));
839 fd_close (dtsock);
840 fd_close (local_sock);
841 return err;
842 case FTPOK:
843 break;
844 default:
845 abort ();
846 }
847
848 if (!opt.server_response)
849 logputs (LOG_VERBOSE, _("done.\n"));
850 expected_bytes = ftp_expected_bytes (ftp_last_respline);
851 } /* do retrieve */
852
853 if (cmd & DO_LIST)
854 {
855 if (!opt.server_response)
856 logputs (LOG_VERBOSE, "==> LIST ... ");
857 /* As Maciej W. Rozycki (macro@ds2.pg.gda.pl) says, `LIST'
858 without arguments is better than `LIST .'; confirmed by
859 RFC959. */
860 err = ftp_list (csock, NULL);
861 /* FTPRERR, WRITEFAILED */
862 switch (err)
863 {
864 case FTPRERR:
865 logputs (LOG_VERBOSE, "\n");
866 logputs (LOG_NOTQUIET, _("\
867Error in server response, closing control connection.\n"));
868 fd_close (csock);
869 con->csock = -1;
870 fd_close (dtsock);
871 fd_close (local_sock);
872 return err;
873 case WRITEFAILED:
874 logputs (LOG_VERBOSE, "\n");
875 logputs (LOG_NOTQUIET,
876 _("Write failed, closing control connection.\n"));
877 fd_close (csock);
878 con->csock = -1;
879 fd_close (dtsock);
880 fd_close (local_sock);
881 return err;
882 case FTPNSFOD:
883 logputs (LOG_VERBOSE, "\n");
884 logprintf (LOG_NOTQUIET, _("No such file or directory `%s'.\n\n"),
885 ".");
886 fd_close (dtsock);
887 fd_close (local_sock);
888 return err;
889 case FTPOK:
890 break;
891 default:
892 abort ();
893 }
894 if (!opt.server_response)
895 logputs (LOG_VERBOSE, _("done.\n"));
896 expected_bytes = ftp_expected_bytes (ftp_last_respline);
897 } /* cmd & DO_LIST */
898
899 if (!(cmd & (DO_LIST | DO_RETR)) || (opt.spider && !(cmd & DO_LIST)))
900 return RETRFINISHED;
901
902 /* Some FTP servers return the total length of file after REST
903 command, others just return the remaining size. */
904 if (*len && restval && expected_bytes
905 && (expected_bytes == *len - restval))
906 {
907 DEBUGP (("Lying FTP server found, adjusting.\n"));
908 expected_bytes = *len;
909 }
910
911 /* If no transmission was required, then everything is OK. */
912 if (!pasv_mode_open) /* we are not using pasive mode so we need
913 to accept */
914 {
915 /* Wait for the server to connect to the address we're waiting
916 at. */
917 dtsock = accept_connection (local_sock);
918 if (dtsock < 0)
919 {
920 logprintf (LOG_NOTQUIET, "accept: %s\n", strerror (errno));
921 return err;
922 }
923 }
924
925 /* Open the file -- if output_stream is set, use it instead. */
926 if (!output_stream || con->cmd & DO_LIST)
927 {
928 mkalldirs (con->target);
929 if (opt.backups)
930 rotate_backups (con->target);
931
932 if (restval)
933 fp = fopen (con->target, "ab");
934 else if (opt.noclobber || opt.always_rest || opt.timestamping || opt.dirstruct
935 || opt.output_document)
936 fp = fopen (con->target, "wb");
937 else
938 {
939 fp = fopen_excl (con->target, 1);
940 if (!fp && errno == EEXIST)
941 {
942 /* We cannot just invent a new name and use it (which is
943 what functions like unique_create typically do)
944 because we told the user we'd use this name.
945 Instead, return and retry the download. */
946 logprintf (LOG_NOTQUIET, _("%s has sprung into existence.\n"),
947 con->target);
948 fd_close (csock);
949 con->csock = -1;
950 fd_close (dtsock);
951 fd_close (local_sock);
952 return FOPEN_EXCL_ERR;
953 }
954 }
955 if (!fp)
956 {
957 logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, strerror (errno));
958 fd_close (csock);
959 con->csock = -1;
960 fd_close (dtsock);
961 fd_close (local_sock);
962 return FOPENERR;
963 }
964 }
965 else
966 fp = output_stream;
967
968 if (*len)
969 {
970 print_length (*len, restval, 1);
971 expected_bytes = *len; /* for get_contents/show_progress */
972 }
973 else if (expected_bytes)
974 print_length (expected_bytes, restval, 0);
975
976 /* Get the contents of the document. */
977 flags = 0;
978 if (restval && rest_failed)
979 flags |= rb_skip_startpos;
980 *len = restval;
981 rd_size = 0;
982 res = fd_read_body (dtsock, fp,
983 expected_bytes ? expected_bytes - restval : 0,
984 restval, &rd_size, len, &con->dltime, flags);
985
986 tms = time_str (NULL);
987 tmrate = retr_rate (rd_size, con->dltime, 0);
988 /* Close data connection socket. */
989 fd_close (dtsock);
990 fd_close (local_sock);
991 /* Close the local file. */
992 {
993 /* Close or flush the file. We have to be careful to check for
994 error here. Checking the result of fwrite() is not enough --
995 errors could go unnoticed! */
996 int flush_res;
997 if (!output_stream || con->cmd & DO_LIST)
998 flush_res = fclose (fp);
999 else
1000 flush_res = fflush (fp);
1001 if (flush_res == EOF)
1002 res = -2;
1003 }
1004
1005 /* If get_contents couldn't write to fp, bail out. */
1006 if (res == -2)
1007 {
1008 logprintf (LOG_NOTQUIET, _("%s: %s, closing control connection.\n"),
1009 con->target, strerror (errno));
1010 fd_close (csock);
1011 con->csock = -1;
1012 return FWRITEERR;
1013 }
1014 else if (res == -1)
1015 {
1016 logprintf (LOG_NOTQUIET, _("%s (%s) - Data connection: %s; "),
1017 tms, tmrate, strerror (errno));
1018 if (opt.server_response)
1019 logputs (LOG_ALWAYS, "\n");
1020 }
1021
1022 /* Get the server to tell us if everything is retrieved. */
1023 err = ftp_response (csock, &respline);
1024 if (err != FTPOK)
1025 {
1026 /* The control connection is decidedly closed. Print the time
1027 only if it hasn't already been printed. */
1028 if (res != -1)
1029 logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
1030 logputs (LOG_NOTQUIET, _("Control connection closed.\n"));
1031 /* If there is an error on the control connection, close it, but
1032 return FTPRETRINT, since there is a possibility that the
1033 whole file was retrieved nevertheless (but that is for
1034 ftp_loop_internal to decide). */
1035 fd_close (csock);
1036 con->csock = -1;
1037 return FTPRETRINT;
1038 } /* err != FTPOK */
1039 /* If retrieval failed for any reason, return FTPRETRINT, but do not
1040 close socket, since the control connection is still alive. If
1041 there is something wrong with the control connection, it will
1042 become apparent later. */
1043 if (*respline != '2')
1044 {
1045 xfree (respline);
1046 if (res != -1)
1047 logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
1048 logputs (LOG_NOTQUIET, _("Data transfer aborted.\n"));
1049 return FTPRETRINT;
1050 }
1051 xfree (respline);
1052
1053 if (res == -1)
1054 {
1055 /* What now? The data connection was erroneous, whereas the
1056 response says everything is OK. We shall play it safe. */
1057 return FTPRETRINT;
1058 }
1059
1060 if (!(cmd & LEAVE_PENDING))
1061 {
1062 /* Closing the socket is faster than sending 'QUIT' and the
1063 effect is the same. */
1064 fd_close (csock);
1065 con->csock = -1;
1066 }
1067 /* If it was a listing, and opt.server_response is true,
1068 print it out. */
1069 if (opt.server_response && (con->cmd & DO_LIST))
1070 {
1071 mkalldirs (con->target);
1072 fp = fopen (con->target, "r");
1073 if (!fp)
1074 logprintf (LOG_ALWAYS, "%s: %s\n", con->target, strerror (errno));
1075 else
1076 {
1077 char *line;
1078 /* The lines are being read with read_whole_line because of
1079 no-buffering on opt.lfile. */
1080 while ((line = read_whole_line (fp)) != NULL)
1081 {
1082 char *p = strchr (line, '\0');
1083 while (p > line && (p[-1] == '\n' || p[-1] == '\r'))
1084 *--p = '\0';
1085 logprintf (LOG_ALWAYS, "%s\n", escnonprint (line));
1086 xfree (line);
1087 }
1088 fclose (fp);
1089 }
1090 } /* con->cmd & DO_LIST && server_response */
1091
1092 return RETRFINISHED;
1093}
1094
1095/* A one-file FTP loop. This is the part where FTP retrieval is
1096 retried, and retried, and retried, and...
1097
1098 This loop either gets commands from con, or (if ON_YOUR_OWN is
1099 set), makes them up to retrieve the file given by the URL. */
1100static uerr_t
1101ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con)
1102{
1103 int count, orig_lp;
1104 wgint restval, len = 0;
1105 char *tms, *locf;
1106 char *tmrate = NULL;
1107 uerr_t err;
1108 struct_stat st;
1109
1110 if (!con->target)
1111 con->target = url_file_name (u);
1112
1113 if (opt.noclobber && file_exists_p (con->target))
1114 {
1115 logprintf (LOG_VERBOSE,
1116 _("File `%s' already there; not retrieving.\n"), con->target);
1117 /* If the file is there, we suppose it's retrieved OK. */
1118 return RETROK;
1119 }
1120
1121 /* Remove it if it's a link. */
1122 remove_link (con->target);
1123 if (!opt.output_document)
1124 locf = con->target;
1125 else
1126 locf = opt.output_document;
1127
1128 count = 0;
1129
1130 if (con->st & ON_YOUR_OWN)
1131 con->st = ON_YOUR_OWN;
1132
1133 orig_lp = con->cmd & LEAVE_PENDING ? 1 : 0;
1134
1135 /* THE loop. */
1136 do
1137 {
1138 /* Increment the pass counter. */
1139 ++count;
1140 sleep_between_retrievals (count);
1141 if (con->st & ON_YOUR_OWN)
1142 {
1143 con->cmd = 0;
1144 con->cmd |= (DO_RETR | LEAVE_PENDING);
1145 if (con->csock != -1)
1146 con->cmd &= ~ (DO_LOGIN | DO_CWD);
1147 else
1148 con->cmd |= (DO_LOGIN | DO_CWD);
1149 }
1150 else /* not on your own */
1151 {
1152 if (con->csock != -1)
1153 con->cmd &= ~DO_LOGIN;
1154 else
1155 con->cmd |= DO_LOGIN;
1156 if (con->st & DONE_CWD)
1157 con->cmd &= ~DO_CWD;
1158 else
1159 con->cmd |= DO_CWD;
1160 }
1161
1162 /* Decide whether or not to restart. */
1163 if (opt.always_rest
1164 && stat (locf, &st) == 0
1165 && S_ISREG (st.st_mode))
1166 /* When -c is used, continue from on-disk size. (Can't use
1167 hstat.len even if count>1 because we don't want a failed
1168 first attempt to clobber existing data.) */
1169 restval = st.st_size;
1170 else if (count > 1)
1171 restval = len; /* start where the previous run left off */
1172 else
1173 restval = 0;
1174
1175 /* Get the current time string. */
1176 tms = time_str (NULL);
1177 /* Print fetch message, if opt.verbose. */
1178 if (opt.verbose)
1179 {
1180 char *hurl = url_string (u, 1);
1181 char tmp[256];
1182 strcpy (tmp, " ");
1183 if (count > 1)
1184 sprintf (tmp, _("(try:%2d)"), count);
1185 logprintf (LOG_VERBOSE, "--%s-- %s\n %s => `%s'\n",
1186 tms, hurl, tmp, locf);
1187#ifdef WINDOWS
1188 ws_changetitle (hurl);
1189#endif
1190 xfree (hurl);
1191 }
1192 /* Send getftp the proper length, if fileinfo was provided. */
1193 if (f)
1194 len = f->size;
1195 else
1196 len = 0;
1197 err = getftp (u, &len, restval, con);
1198
1199 if (con->csock != -1)
1200 con->st &= ~DONE_CWD;
1201 else
1202 con->st |= DONE_CWD;
1203
1204 switch (err)
1205 {
1206 case HOSTERR: case CONIMPOSSIBLE: case FWRITEERR: case FOPENERR:
1207 case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case CONTNOTSUPPORTED:
1208 /* Fatal errors, give up. */
1209 return err;
1210 case CONSOCKERR: case CONERROR: case FTPSRVERR: case FTPRERR:
1211 case WRITEFAILED: case FTPUNKNOWNTYPE: case FTPSYSERR:
1212 case FTPPORTERR: case FTPLOGREFUSED: case FTPINVPASV:
1213 case FOPEN_EXCL_ERR:
1214 printwhat (count, opt.ntry);
1215 /* non-fatal errors */
1216 if (err == FOPEN_EXCL_ERR)
1217 {
1218 /* Re-determine the file name. */
1219 xfree_null (con->target);
1220 con->target = url_file_name (u);
1221 locf = con->target;
1222 }
1223 continue;
1224 case FTPRETRINT:
1225 /* If the control connection was closed, the retrieval
1226 will be considered OK if f->size == len. */
1227 if (!f || len != f->size)
1228 {
1229 printwhat (count, opt.ntry);
1230 continue;
1231 }
1232 break;
1233 case RETRFINISHED:
1234 /* Great! */
1235 break;
1236 default:
1237 /* Not as great. */
1238 abort ();
1239 }
1240 tms = time_str (NULL);
1241 if (!opt.spider)
1242 tmrate = retr_rate (len - restval, con->dltime, 0);
1243
1244 /* If we get out of the switch above without continue'ing, we've
1245 successfully downloaded a file. Remember this fact. */
1246 downloaded_file (FILE_DOWNLOADED_NORMALLY, locf);
1247
1248 if (con->st & ON_YOUR_OWN)
1249 {
1250 fd_close (con->csock);
1251 con->csock = -1;
1252 }
1253 if (!opt.spider)
1254 logprintf (LOG_VERBOSE, _("%s (%s) - `%s' saved [%s]\n\n"),
1255 tms, tmrate, locf, number_to_static_string (len));
1256 if (!opt.verbose && !opt.quiet)
1257 {
1258 /* Need to hide the password from the URL. The `if' is here
1259 so that we don't do the needless allocation every
1260 time. */
1261 char *hurl = url_string (u, 1);
1262 logprintf (LOG_NONVERBOSE, "%s URL: %s [%s] -> \"%s\" [%d]\n",
1263 tms, hurl, number_to_static_string (len), locf, count);
1264 xfree (hurl);
1265 }
1266
1267 if ((con->cmd & DO_LIST))
1268 /* This is a directory listing file. */
1269 {
1270 if (!opt.remove_listing)
1271 /* --dont-remove-listing was specified, so do count this towards the
1272 number of bytes and files downloaded. */
1273 {
1274 total_downloaded_bytes += len;
1275 opt.numurls++;
1276 }
1277
1278 /* Deletion of listing files is not controlled by --delete-after, but
1279 by the more specific option --dont-remove-listing, and the code
1280 to do this deletion is in another function. */
1281 }
1282 else if (!opt.spider)
1283 /* This is not a directory listing file. */
1284 {
1285 /* Unlike directory listing files, don't pretend normal files weren't
1286 downloaded if they're going to be deleted. People seeding proxies,
1287 for instance, may want to know how many bytes and files they've
1288 downloaded through it. */
1289 total_downloaded_bytes += len;
1290 opt.numurls++;
1291
1292 if (opt.delete_after)
1293 {
1294 DEBUGP (("\
1295Removing file due to --delete-after in ftp_loop_internal():\n"));
1296 logprintf (LOG_VERBOSE, _("Removing %s.\n"), locf);
1297 if (unlink (locf))
1298 logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1299 }
1300 }
1301
1302 /* Restore the original leave-pendingness. */
1303 if (orig_lp)
1304 con->cmd |= LEAVE_PENDING;
1305 else
1306 con->cmd &= ~LEAVE_PENDING;
1307 return RETROK;
1308 } while (!opt.ntry || (count < opt.ntry));
1309
1310 if (con->csock != -1 && (con->st & ON_YOUR_OWN))
1311 {
1312 fd_close (con->csock);
1313 con->csock = -1;
1314 }
1315 return TRYLIMEXC;
1316}
1317
1318/* Return the directory listing in a reusable format. The directory
1319 is specifed in u->dir. */
1320uerr_t
1321ftp_get_listing (struct url *u, ccon *con, struct fileinfo **f)
1322{
1323 uerr_t err;
1324 char *uf; /* url file name */
1325 char *lf; /* list file name */
1326 char *old_target = con->target;
1327
1328 con->st &= ~ON_YOUR_OWN;
1329 con->cmd |= (DO_LIST | LEAVE_PENDING);
1330 con->cmd &= ~DO_RETR;
1331
1332 /* Find the listing file name. We do it by taking the file name of
1333 the URL and replacing the last component with the listing file
1334 name. */
1335 uf = url_file_name (u);
1336 lf = file_merge (uf, LIST_FILENAME);
1337 xfree (uf);
1338 DEBUGP ((_("Using `%s' as listing tmp file.\n"), lf));
1339
1340 con->target = lf;
1341 err = ftp_loop_internal (u, NULL, con);
1342 con->target = old_target;
1343
1344 if (err == RETROK)
1345 *f = ftp_parse_ls (lf, con->rs);
1346 else
1347 *f = NULL;
1348 if (opt.remove_listing)
1349 {
1350 if (unlink (lf))
1351 logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1352 else
1353 logprintf (LOG_VERBOSE, _("Removed `%s'.\n"), lf);
1354 }
1355 xfree (lf);
1356 con->cmd &= ~DO_LIST;
1357 return err;
1358}
1359
1360static uerr_t ftp_retrieve_dirs PARAMS ((struct url *, struct fileinfo *,
1361 ccon *));
1362static uerr_t ftp_retrieve_glob PARAMS ((struct url *, ccon *, int));
1363static struct fileinfo *delelement PARAMS ((struct fileinfo *,
1364 struct fileinfo **));
1365static void freefileinfo PARAMS ((struct fileinfo *f));
1366
1367/* Retrieve a list of files given in struct fileinfo linked list. If
1368 a file is a symbolic link, do not retrieve it, but rather try to
1369 set up a similar link on the local disk, if the symlinks are
1370 supported.
1371
1372 If opt.recursive is set, after all files have been retrieved,
1373 ftp_retrieve_dirs will be called to retrieve the directories. */
1374static uerr_t
1375ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con)
1376{
1377 static int depth = 0;
1378 uerr_t err;
1379 struct fileinfo *orig;
1380 wgint local_size;
1381 time_t tml;
1382 int dlthis;
1383
1384 /* Increase the depth. */
1385 ++depth;
1386 if (opt.reclevel != INFINITE_RECURSION && depth > opt.reclevel)
1387 {
1388 DEBUGP ((_("Recursion depth %d exceeded max. depth %d.\n"),
1389 depth, opt.reclevel));
1390 --depth;
1391 return RECLEVELEXC;
1392 }
1393
1394 assert (f != NULL);
1395 orig = f;
1396
1397 con->st &= ~ON_YOUR_OWN;
1398 if (!(con->st & DONE_CWD))
1399 con->cmd |= DO_CWD;
1400 else
1401 con->cmd &= ~DO_CWD;
1402 con->cmd |= (DO_RETR | LEAVE_PENDING);
1403
1404 if (con->csock < 0)
1405 con->cmd |= DO_LOGIN;
1406 else
1407 con->cmd &= ~DO_LOGIN;
1408
1409 err = RETROK; /* in case it's not used */
1410
1411 while (f)
1412 {
1413 char *old_target, *ofile;
1414
1415 if (opt.quota && total_downloaded_bytes > opt.quota)
1416 {
1417 --depth;
1418 return QUOTEXC;
1419 }
1420 old_target = con->target;
1421
1422 ofile = xstrdup (u->file);
1423 url_set_file (u, f->name);
1424
1425 con->target = url_file_name (u);
1426 err = RETROK;
1427
1428 dlthis = 1;
1429 if (opt.timestamping && f->type == FT_PLAINFILE)
1430 {
1431 struct_stat st;
1432 /* If conversion of HTML files retrieved via FTP is ever implemented,
1433 we'll need to stat() <file>.orig here when -K has been specified.
1434 I'm not implementing it now since files on an FTP server are much
1435 more likely than files on an HTTP server to legitimately have a
1436 .orig suffix. */
1437 if (!stat (con->target, &st))
1438 {
1439 int eq_size;
1440 int cor_val;
1441 /* Else, get it from the file. */
1442 local_size = st.st_size;
1443 tml = st.st_mtime;
1444#ifdef WINDOWS
1445 /* Modification time granularity is 2 seconds for Windows, so
1446 increase local time by 1 second for later comparison. */
1447 tml++;
1448#endif
1449 /* Compare file sizes only for servers that tell us correct
1450 values. Assumme sizes being equal for servers that lie
1451 about file size. */
1452 cor_val = (con->rs == ST_UNIX || con->rs == ST_WINNT);
1453 eq_size = cor_val ? (local_size == f->size) : 1 ;
1454 if (f->tstamp <= tml && eq_size)
1455 {
1456 /* Remote file is older, file sizes can be compared and
1457 are both equal. */
1458 logprintf (LOG_VERBOSE, _("\
1459Remote file no newer than local file `%s' -- not retrieving.\n"), con->target);
1460 dlthis = 0;
1461 }
1462 else if (eq_size)
1463 {
1464 /* Remote file is newer or sizes cannot be matched */
1465 logprintf (LOG_VERBOSE, _("\
1466Remote file is newer than local file `%s' -- retrieving.\n\n"),
1467 con->target);
1468 }
1469 else
1470 {
1471 /* Sizes do not match */
1472 logprintf (LOG_VERBOSE, _("\
1473The sizes do not match (local %s) -- retrieving.\n\n"),
1474 number_to_static_string (local_size));
1475 }
1476 }
1477 } /* opt.timestamping && f->type == FT_PLAINFILE */
1478 switch (f->type)
1479 {
1480 case FT_SYMLINK:
1481 /* If opt.retr_symlinks is defined, we treat symlinks as
1482 if they were normal files. There is currently no way
1483 to distinguish whether they might be directories, and
1484 follow them. */
1485 if (!opt.retr_symlinks)
1486 {
1487#ifdef HAVE_SYMLINK
1488 if (!f->linkto)
1489 logputs (LOG_NOTQUIET,
1490 _("Invalid name of the symlink, skipping.\n"));
1491 else
1492 {
1493 struct_stat st;
1494 /* Check whether we already have the correct
1495 symbolic link. */
1496 int rc = lstat (con->target, &st);
1497 if (rc == 0)
1498 {
1499 size_t len = strlen (f->linkto) + 1;
1500 if (S_ISLNK (st.st_mode))
1501 {
1502 char *link_target = (char *)alloca (len);
1503 size_t n = readlink (con->target, link_target, len);
1504 if ((n == len - 1)
1505 && (memcmp (link_target, f->linkto, n) == 0))
1506 {
1507 logprintf (LOG_VERBOSE, _("\
1508Already have correct symlink %s -> %s\n\n"),
1509 con->target, escnonprint (f->linkto));
1510 dlthis = 0;
1511 break;
1512 }
1513 }
1514 }
1515 logprintf (LOG_VERBOSE, _("Creating symlink %s -> %s\n"),
1516 con->target, escnonprint (f->linkto));
1517 /* Unlink before creating symlink! */
1518 unlink (con->target);
1519 if (symlink (f->linkto, con->target) == -1)
1520 logprintf (LOG_NOTQUIET, "symlink: %s\n", strerror (errno));
1521 logputs (LOG_VERBOSE, "\n");
1522 } /* have f->linkto */
1523#else /* not HAVE_SYMLINK */
1524 logprintf (LOG_NOTQUIET,
1525 _("Symlinks not supported, skipping symlink `%s'.\n"),
1526 con->target);
1527#endif /* not HAVE_SYMLINK */
1528 }
1529 else /* opt.retr_symlinks */
1530 {
1531 if (dlthis)
1532 err = ftp_loop_internal (u, f, con);
1533 } /* opt.retr_symlinks */
1534 break;
1535 case FT_DIRECTORY:
1536 if (!opt.recursive)
1537 logprintf (LOG_NOTQUIET, _("Skipping directory `%s'.\n"),
1538 escnonprint (f->name));
1539 break;
1540 case FT_PLAINFILE:
1541 /* Call the retrieve loop. */
1542 if (dlthis)
1543 err = ftp_loop_internal (u, f, con);
1544 break;
1545 case FT_UNKNOWN:
1546 logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"),
1547 escnonprint (f->name));
1548 break;
1549 } /* switch */
1550
1551 /* Set the time-stamp information to the local file. Symlinks
1552 are not to be stamped because it sets the stamp on the
1553 original. :( */
1554 if (!(f->type == FT_SYMLINK && !opt.retr_symlinks)
1555 && f->tstamp != -1
1556 && dlthis
1557 && file_exists_p (con->target))
1558 {
1559 /* #### This code repeats in http.c and ftp.c. Move it to a
1560 function! */
1561 const char *fl = NULL;
1562 if (opt.output_document)
1563 {
1564 if (output_stream_regular)
1565 fl = opt.output_document;
1566 }
1567 else
1568 fl = con->target;
1569 if (fl)
1570 touch (fl, f->tstamp);
1571 }
1572 else if (f->tstamp == -1)
1573 logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"), con->target);
1574
1575 if (f->perms && f->type == FT_PLAINFILE && dlthis)
1576 {
1577 if (opt.preserve_perm)
1578 chmod (con->target, f->perms);
1579 }
1580 else
1581 DEBUGP (("Unrecognized permissions for %s.\n", con->target));
1582
1583 xfree (con->target);
1584 con->target = old_target;
1585
1586 url_set_file (u, ofile);
1587 xfree (ofile);
1588
1589 /* Break on fatals. */
1590 if (err == QUOTEXC || err == HOSTERR || err == FWRITEERR)
1591 break;
1592 con->cmd &= ~ (DO_CWD | DO_LOGIN);
1593 f = f->next;
1594 }
1595
1596 /* We do not want to call ftp_retrieve_dirs here */
1597 if (opt.recursive &&
1598 !(opt.reclevel != INFINITE_RECURSION && depth >= opt.reclevel))
1599 err = ftp_retrieve_dirs (u, orig, con);
1600 else if (opt.recursive)
1601 DEBUGP ((_("Will not retrieve dirs since depth is %d (max %d).\n"),
1602 depth, opt.reclevel));
1603 --depth;
1604 return err;
1605}
1606
1607/* Retrieve the directories given in a file list. This function works
1608 by simply going through the linked list and calling
1609 ftp_retrieve_glob on each directory entry. The function knows
1610 about excluded directories. */
1611static uerr_t
1612ftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con)
1613{
1614 char *container = NULL;
1615 int container_size = 0;
1616
1617 for (; f; f = f->next)
1618 {
1619 int size;
1620 char *odir, *newdir;
1621
1622 if (opt.quota && total_downloaded_bytes > opt.quota)
1623 break;
1624 if (f->type != FT_DIRECTORY)
1625 continue;
1626
1627 /* Allocate u->dir off stack, but reallocate only if a larger
1628 string is needed. It's a pity there's no "realloca" for an
1629 item on the bottom of the stack. */
1630 size = strlen (u->dir) + 1 + strlen (f->name) + 1;
1631 if (size > container_size)
1632 container = (char *)alloca (size);
1633 newdir = container;
1634
1635 odir = u->dir;
1636 if (*odir == '\0'
1637 || (*odir == '/' && *(odir + 1) == '\0'))
1638 /* If ODIR is empty or just "/", simply append f->name to
1639 ODIR. (In the former case, to preserve u->dir being
1640 relative; in the latter case, to avoid double slash.) */
1641 sprintf (newdir, "%s%s", odir, f->name);
1642 else
1643 /* Else, use a separator. */
1644 sprintf (newdir, "%s/%s", odir, f->name);
1645
1646 DEBUGP (("Composing new CWD relative to the initial directory.\n"));
1647 DEBUGP ((" odir = '%s'\n f->name = '%s'\n newdir = '%s'\n\n",
1648 odir, f->name, newdir));
1649 if (!accdir (newdir, ALLABS))
1650 {
1651 logprintf (LOG_VERBOSE, _("\
1652Not descending to `%s' as it is excluded/not-included.\n"),
1653 escnonprint (newdir));
1654 continue;
1655 }
1656
1657 con->st &= ~DONE_CWD;
1658
1659 odir = xstrdup (u->dir); /* because url_set_dir will free
1660 u->dir. */
1661 url_set_dir (u, newdir);
1662 ftp_retrieve_glob (u, con, GLOB_GETALL);
1663 url_set_dir (u, odir);
1664 xfree (odir);
1665
1666 /* Set the time-stamp? */
1667 }
1668
1669 if (opt.quota && total_downloaded_bytes > opt.quota)
1670 return QUOTEXC;
1671 else
1672 return RETROK;
1673}
1674
1675/* Return non-zero if S has a leading '/' or contains '../' */
1676static int
1677has_insecure_name_p (const char *s)
1678{
1679 if (*s == '/')
1680 return 1;
1681
1682 if (strstr (s, "../") != 0)
1683 return 1;
1684
1685 return 0;
1686}
1687
1688/* A near-top-level function to retrieve the files in a directory.
1689 The function calls ftp_get_listing, to get a linked list of files.
1690 Then it weeds out the file names that do not match the pattern.
1691 ftp_retrieve_list is called with this updated list as an argument.
1692
1693 If the argument ACTION is GLOB_GETONE, just download the file (but
1694 first get the listing, so that the time-stamp is heeded); if it's
1695 GLOB_GLOBALL, use globbing; if it's GLOB_GETALL, download the whole
1696 directory. */
1697static uerr_t
1698ftp_retrieve_glob (struct url *u, ccon *con, int action)
1699{
1700 struct fileinfo *f, *start;
1701 uerr_t res;
1702
1703 con->cmd |= LEAVE_PENDING;
1704
1705 res = ftp_get_listing (u, con, &start);
1706 if (res != RETROK)
1707 return res;
1708 /* First: weed out that do not conform the global rules given in
1709 opt.accepts and opt.rejects. */
1710 if (opt.accepts || opt.rejects)
1711 {
1712 f = start;
1713 while (f)
1714 {
1715 if (f->type != FT_DIRECTORY && !acceptable (f->name))
1716 {
1717 logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"),
1718 escnonprint (f->name));
1719 f = delelement (f, &start);
1720 }
1721 else
1722 f = f->next;
1723 }
1724 }
1725 /* Remove all files with possible harmful names */
1726 f = start;
1727 while (f)
1728 {
1729 if (has_insecure_name_p (f->name))
1730 {
1731 logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"),
1732 escnonprint (f->name));
1733 f = delelement (f, &start);
1734 }
1735 else
1736 f = f->next;
1737 }
1738 /* Now weed out the files that do not match our globbing pattern.
1739 If we are dealing with a globbing pattern, that is. */
1740 if (*u->file && (action == GLOB_GLOBALL || action == GLOB_GETONE))
1741 {
1742 int matchres = 0;
1743
1744 f = start;
1745 while (f)
1746 {
1747 matchres = fnmatch (u->file, f->name, 0);
1748 if (matchres == -1)
1749 {
1750 logprintf (LOG_NOTQUIET, "%s: %s\n", con->target,
1751 strerror (errno));
1752 break;
1753 }
1754 if (matchres == FNM_NOMATCH)
1755 f = delelement (f, &start); /* delete the element from the list */
1756 else
1757 f = f->next; /* leave the element in the list */
1758 }
1759 if (matchres == -1)
1760 {
1761 freefileinfo (start);
1762 return RETRBADPATTERN;
1763 }
1764 }
1765 if (start)
1766 {
1767 /* Just get everything. */
1768 ftp_retrieve_list (u, start, con);
1769 }
1770 else if (!start)
1771 {
1772 if (action == GLOB_GLOBALL)
1773 {
1774 /* No luck. */
1775 /* #### This message SUCKS. We should see what was the
1776 reason that nothing was retrieved. */
1777 logprintf (LOG_VERBOSE, _("No matches on pattern `%s'.\n"),
1778 escnonprint (u->file));
1779 }
1780 else /* GLOB_GETONE or GLOB_GETALL */
1781 {
1782 /* Let's try retrieving it anyway. */
1783 con->st |= ON_YOUR_OWN;
1784 res = ftp_loop_internal (u, NULL, con);
1785 return res;
1786 }
1787 }
1788 freefileinfo (start);
1789 if (opt.quota && total_downloaded_bytes > opt.quota)
1790 return QUOTEXC;
1791 else
1792 /* #### Should we return `res' here? */
1793 return RETROK;
1794}
1795
1796/* The wrapper that calls an appropriate routine according to contents
1797 of URL. Inherently, its capabilities are limited on what can be
1798 encoded into a URL. */
1799uerr_t
1800ftp_loop (struct url *u, int *dt, struct url *proxy)
1801{
1802 ccon con; /* FTP connection */
1803 uerr_t res;
1804
1805 *dt = 0;
1806
1807 xzero (con);
1808
1809 con.csock = -1;
1810 con.st = ON_YOUR_OWN;
1811 con.rs = ST_UNIX;
1812 con.id = NULL;
1813 con.proxy = proxy;
1814
1815 /* If the file name is empty, the user probably wants a directory
1816 index. We'll provide one, properly HTML-ized. Unless
1817 opt.htmlify is 0, of course. :-) */
1818 if (!*u->file && !opt.recursive)
1819 {
1820 struct fileinfo *f;
1821 res = ftp_get_listing (u, &con, &f);
1822
1823 if (res == RETROK)
1824 {
1825 if (opt.htmlify && !opt.spider)
1826 {
1827 char *filename = (opt.output_document
1828 ? xstrdup (opt.output_document)
1829 : (con.target ? xstrdup (con.target)
1830 : url_file_name (u)));
1831 res = ftp_index (filename, u, f);
1832 if (res == FTPOK && opt.verbose)
1833 {
1834 if (!opt.output_document)
1835 {
1836 struct_stat st;
1837 wgint sz;
1838 if (stat (filename, &st) == 0)
1839 sz = st.st_size;
1840 else
1841 sz = -1;
1842 logprintf (LOG_NOTQUIET,
1843 _("Wrote HTML-ized index to `%s' [%s].\n"),
1844 filename, number_to_static_string (sz));
1845 }
1846 else
1847 logprintf (LOG_NOTQUIET,
1848 _("Wrote HTML-ized index to `%s'.\n"),
1849 filename);
1850 }
1851 xfree (filename);
1852 }
1853 freefileinfo (f);
1854 }
1855 }
1856 else
1857 {
1858 int ispattern = 0;
1859 if (opt.ftp_glob)
1860 {
1861 /* Treat the URL as a pattern if the file name part of the
1862 URL path contains wildcards. (Don't check for u->file
1863 because it is unescaped and therefore doesn't leave users
1864 the option to escape literal '*' as %2A.) */
1865 char *file_part = strrchr (u->path, '/');
1866 if (!file_part)
1867 file_part = u->path;
1868 ispattern = has_wildcards_p (file_part);
1869 }
1870 if (ispattern || opt.recursive || opt.timestamping)
1871 {
1872 /* ftp_retrieve_glob is a catch-all function that gets called
1873 if we need globbing, time-stamping or recursion. Its
1874 third argument is just what we really need. */
1875 res = ftp_retrieve_glob (u, &con,
1876 ispattern ? GLOB_GLOBALL : GLOB_GETONE);
1877 }
1878 else
1879 res = ftp_loop_internal (u, NULL, &con);
1880 }
1881 if (res == FTPOK)
1882 res = RETROK;
1883 if (res == RETROK)
1884 *dt |= RETROKF;
1885 /* If a connection was left, quench it. */
1886 if (con.csock != -1)
1887 fd_close (con.csock);
1888 xfree_null (con.id);
1889 con.id = NULL;
1890 xfree_null (con.target);
1891 con.target = NULL;
1892 return res;
1893}
1894
1895/* Delete an element from the fileinfo linked list. Returns the
1896 address of the next element, or NULL if the list is exhausted. It
1897 can modify the start of the list. */
1898static struct fileinfo *
1899delelement (struct fileinfo *f, struct fileinfo **start)
1900{
1901 struct fileinfo *prev = f->prev;
1902 struct fileinfo *next = f->next;
1903
1904 xfree (f->name);
1905 xfree_null (f->linkto);
1906 xfree (f);
1907
1908 if (next)
1909 next->prev = prev;
1910 if (prev)
1911 prev->next = next;
1912 else
1913 *start = next;
1914 return next;
1915}
1916
1917/* Free the fileinfo linked list of files. */
1918static void
1919freefileinfo (struct fileinfo *f)
1920{
1921 while (f)
1922 {
1923 struct fileinfo *next = f->next;
1924 xfree (f->name);
1925 if (f->linkto)
1926 xfree (f->linkto);
1927 xfree (f);
1928 f = next;
1929 }
1930}
Note: See TracBrowser for help on using the repository browser.