1 /* File Transfer Protocol support.
2 Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001
3 Free Software Foundation, Inc.
5 This file is part of GNU Wget.
7 GNU Wget is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GNU Wget is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Wget; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 In addition, as a special exception, the Free Software Foundation
22 gives permission to link the code of its release of Wget with the
23 OpenSSL project's "OpenSSL" library (or with modified versions of it
24 that use the same license as the "OpenSSL" library), and distribute
25 the linked executables. You must obey the GNU General Public License
26 in all respects for all of the code used other than "OpenSSL". If you
27 modify this file, you may extend this exception to your version of the
28 file, but you are not obligated to do so. If you do not wish to do
29 so, delete this exception statement from your version. */
43 #include <sys/types.h>
56 #include "convert.h" /* for downloaded_file */
57 #include "recur.h" /* for INFINITE_RECURSION */
63 extern LARGE_INT total_downloaded_bytes;
65 /* File where the "ls -al" listing will be saved. */
66 #define LIST_FILENAME ".listing"
68 extern char ftp_last_respline[];
72 int st; /* connection status */
73 int cmd; /* command code */
74 struct rbuf rbuf; /* control connection buffer */
75 double dltime; /* time of the download in msecs */
76 enum stype rs; /* remote system reported by ftp server */
77 char *id; /* initial directory */
78 char *target; /* target file name */
79 struct url *proxy; /* FTWK-style proxy */
83 /* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in
84 the string S, and return the number converted to long, if found, 0
87 ftp_expected_bytes (const char *s)
93 while (*s && *s != '(')
97 for (++s; *s && ISSPACE (*s); s++);
105 res = (*s - '0') + 10 * res;
108 while (*s && ISDIGIT (*s));
111 while (*s && ISSPACE (*s))
115 if (TOLOWER (*s) != 'b')
117 if (strncasecmp (s, "byte", 4))
129 struct sockaddr_storage ss;
130 struct sockaddr *sa = (struct sockaddr *)&ss;
131 socklen_t len = sizeof (ss);
135 if (getpeername (fd, sa, &len) < 0)
136 /* Mauro Tortonesi: HOW DO WE HANDLE THIS ERROR? */
139 return sa->sa_family;
143 * This function sets up a passive data connection with the FTP server.
144 * It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv.
147 ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, int *port)
152 family = getfamily (rbuf->fd);
153 assert (family == AF_INET || family == AF_INET6);
155 /* If our control connection is over IPv6, then we first try EPSV and then
156 * LPSV if the former is not supported. If the control connection is over
157 * IPv4, we simply issue the good old PASV request. */
158 if (family == AF_INET6)
160 if (!opt.server_response)
161 logputs (LOG_VERBOSE, "==> EPSV ... ");
162 err = ftp_epsv (rbuf, addr, port);
164 /* If EPSV is not supported try LPSV */
165 if (err == FTPNOPASV)
167 if (!opt.server_response)
168 logputs (LOG_VERBOSE, "==> LPSV ... ");
169 err = ftp_lpsv (rbuf, addr, port);
174 if (!opt.server_response)
175 logputs (LOG_VERBOSE, "==> PASV ... ");
176 err = ftp_pasv (rbuf, addr, port);
183 * This function sets up an active data connection with the FTP server.
184 * It is merely a wrapper around ftp_eprt, ftp_lprt and ftp_port.
187 ftp_do_port (struct rbuf *rbuf, int *local_sock)
192 assert (rbuf != NULL);
193 assert (rbuf_initialized_p (rbuf));
195 family = getfamily (rbuf->fd);
196 assert (family == AF_INET || family == AF_INET6);
198 /* If our control connection is over IPv6, then we first try EPRT and then
199 * LPRT if the former is not supported. If the control connection is over
200 * IPv4, we simply issue the good old PORT request. */
201 if (family == AF_INET6)
203 if (!opt.server_response)
204 logputs (LOG_VERBOSE, "==> EPRT ... ");
205 err = ftp_eprt (rbuf, local_sock);
207 /* If EPRT is not supported try LPRT */
208 if (err == FTPPORTERR)
210 if (!opt.server_response)
211 logputs (LOG_VERBOSE, "==> LPRT ... ");
212 err = ftp_lprt (rbuf, local_sock);
217 if (!opt.server_response)
218 logputs (LOG_VERBOSE, "==> PORT ... ");
219 err = ftp_port (rbuf, local_sock);
227 ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, int *port)
229 if (!opt.server_response)
230 logputs (LOG_VERBOSE, "==> PASV ... ");
231 return ftp_pasv (rbuf, addr, port);
235 ftp_do_port (struct rbuf *rbuf, int *local_sock)
237 if (!opt.server_response)
238 logputs (LOG_VERBOSE, "==> PORT ... ");
239 return ftp_port (rbuf, local_sock);
243 /* Retrieves a file with denoted parameters through opening an FTP
244 connection to the server. It always closes the data connection,
245 and closes the control connection in case of error. */
247 getftp (struct url *u, long *len, long restval, ccon *con)
249 int csock, dtsock, local_sock, res;
252 char *user, *passwd, *respline;
255 int pasv_mode_open = 0;
256 long expected_bytes = 0L;
258 assert (con != NULL);
259 assert (con->target != NULL);
261 /* Debug-check of the sanity of the request by making sure that LIST
262 and RETR are never both requested (since we can handle only one
264 assert (!((cmd & DO_LIST) && (cmd & DO_RETR)));
265 /* Make sure that at least *something* is requested. */
266 assert ((cmd & (DO_LIST | DO_CWD | DO_RETR | DO_LOGIN)) != 0);
270 search_netrc (u->host, (const char **)&user, (const char **)&passwd, 1);
271 user = user ? user : opt.ftp_acc;
272 passwd = passwd ? passwd : opt.ftp_pass;
273 assert (user && passwd);
279 if (!(cmd & DO_LOGIN))
280 csock = RBUF_FD (&con->rbuf);
281 else /* cmd & DO_LOGIN */
284 char *host = con->proxy ? con->proxy->host : u->host;
285 int port = con->proxy ? con->proxy->port : u->port;
286 char *logname = user;
290 /* If proxy is in use, log in as username@target-site. */
291 logname = xmalloc (strlen (user) + 1 + strlen (u->host) + 1);
292 sprintf (logname, "%s@%s", user, u->host);
295 /* Login to the server: */
297 /* First: Establish the control connection. */
299 csock = connect_to_host (host, port);
303 return CONNECT_ERROR (errno);
305 if (cmd & LEAVE_PENDING)
306 rbuf_initialize (&con->rbuf, csock);
308 rbuf_uninitialize (&con->rbuf);
310 /* Since this is a new connection, we may safely discard
311 anything left in the buffer. */
312 rbuf_discard (&con->rbuf);
314 /* Second: Login with proper USER/PASS sequence. */
315 logprintf (LOG_VERBOSE, _("Logging in as %s ... "), user);
316 if (opt.server_response)
317 logputs (LOG_ALWAYS, "\n");
318 err = ftp_login (&con->rbuf, logname, passwd);
323 /* FTPRERR, FTPSRVERR, WRITEFAILED, FTPLOGREFUSED, FTPLOGINC */
327 logputs (LOG_VERBOSE, "\n");
328 logputs (LOG_NOTQUIET, _("\
329 Error in server response, closing control connection.\n"));
331 rbuf_uninitialize (&con->rbuf);
335 logputs (LOG_VERBOSE, "\n");
336 logputs (LOG_NOTQUIET, _("Error in server greeting.\n"));
338 rbuf_uninitialize (&con->rbuf);
342 logputs (LOG_VERBOSE, "\n");
343 logputs (LOG_NOTQUIET,
344 _("Write failed, closing control connection.\n"));
346 rbuf_uninitialize (&con->rbuf);
350 logputs (LOG_VERBOSE, "\n");
351 logputs (LOG_NOTQUIET, _("The server refuses login.\n"));
353 rbuf_uninitialize (&con->rbuf);
354 return FTPLOGREFUSED;
357 logputs (LOG_VERBOSE, "\n");
358 logputs (LOG_NOTQUIET, _("Login incorrect.\n"));
360 rbuf_uninitialize (&con->rbuf);
364 if (!opt.server_response)
365 logputs (LOG_VERBOSE, _("Logged in!\n"));
372 /* Third: Get the system type */
373 if (!opt.server_response)
374 logprintf (LOG_VERBOSE, "==> SYST ... ");
375 err = ftp_syst (&con->rbuf, &con->rs);
380 logputs (LOG_VERBOSE, "\n");
381 logputs (LOG_NOTQUIET, _("\
382 Error in server response, closing control connection.\n"));
384 rbuf_uninitialize (&con->rbuf);
388 logputs (LOG_VERBOSE, "\n");
389 logputs (LOG_NOTQUIET,
390 _("Server error, can't determine system type.\n"));
393 /* Everything is OK. */
399 if (!opt.server_response && err != FTPSRVERR)
400 logputs (LOG_VERBOSE, _("done. "));
402 /* Fourth: Find the initial ftp directory */
404 if (!opt.server_response)
405 logprintf (LOG_VERBOSE, "==> PWD ... ");
406 err = ftp_pwd(&con->rbuf, &con->id);
411 logputs (LOG_VERBOSE, "\n");
412 logputs (LOG_NOTQUIET, _("\
413 Error in server response, closing control connection.\n"));
415 rbuf_uninitialize (&con->rbuf);
419 /* PWD unsupported -- assume "/". */
420 xfree_null (con->id);
421 con->id = xstrdup ("/");
424 /* Everything is OK. */
430 /* VMS will report something like "PUB$DEVICE:[INITIAL.FOLDER]".
431 Convert it to "/INITIAL/FOLDER" */
432 if (con->rs == ST_VMS)
434 char *path = strchr (con->id, '[');
435 char *pathend = path ? strchr (path + 1, ']') : NULL;
436 if (!path || !pathend)
437 DEBUGP (("Initial VMS directory not in the form [...]!\n"));
440 char *idir = con->id;
441 DEBUGP (("Preprocessing the initial VMS directory\n"));
442 DEBUGP ((" old = '%s'\n", con->id));
443 /* We do the conversion in-place by copying the stuff
444 between [ and ] to the beginning, and changing dots
445 to slashes at the same time. */
447 for (++path; path < pathend; path++, idir++)
448 *idir = *path == '.' ? '/' : *path;
450 DEBUGP ((" new = '%s'\n\n", con->id));
453 if (!opt.server_response)
454 logputs (LOG_VERBOSE, _("done.\n"));
456 /* Fifth: Set the FTP type. */
457 type_char = ftp_process_type (u->params);
458 if (!opt.server_response)
459 logprintf (LOG_VERBOSE, "==> TYPE %c ... ", type_char);
460 err = ftp_type (&con->rbuf, type_char);
461 /* FTPRERR, WRITEFAILED, FTPUNKNOWNTYPE */
465 logputs (LOG_VERBOSE, "\n");
466 logputs (LOG_NOTQUIET, _("\
467 Error in server response, closing control connection.\n"));
469 rbuf_uninitialize (&con->rbuf);
473 logputs (LOG_VERBOSE, "\n");
474 logputs (LOG_NOTQUIET,
475 _("Write failed, closing control connection.\n"));
477 rbuf_uninitialize (&con->rbuf);
481 logputs (LOG_VERBOSE, "\n");
482 logprintf (LOG_NOTQUIET,
483 _("Unknown type `%c', closing control connection.\n"),
486 rbuf_uninitialize (&con->rbuf);
489 /* Everything is OK. */
495 if (!opt.server_response)
496 logputs (LOG_VERBOSE, _("done. "));
502 logputs (LOG_VERBOSE, _("==> CWD not needed.\n"));
505 char *target = u->dir;
507 DEBUGP (("changing working directory\n"));
509 /* Change working directory. To change to a non-absolute
510 Unix directory, we need to prepend initial directory
511 (con->id) to it. Absolute directories "just work".
513 A relative directory is one that does not begin with '/'
514 and, on non-Unix OS'es, one that doesn't begin with
517 This is not done for OS400, which doesn't use
518 "/"-delimited directories, nor does it support directory
519 hierarchies. "CWD foo" followed by "CWD bar" leaves us
520 in "bar", not in "foo/bar", as would be customary
524 && !(con->rs != ST_UNIX
525 && ISALPHA (target[0])
527 && con->rs != ST_OS400)
529 int idlen = strlen (con->id);
532 /* Strip trailing slash(es) from con->id. */
533 while (idlen > 0 && con->id[idlen - 1] == '/')
535 p = ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1);
536 memcpy (p, con->id, idlen);
541 DEBUGP (("Prepended initial PWD to relative path:\n"));
542 DEBUGP ((" pwd: '%s'\n old: '%s'\n new: '%s'\n",
543 con->id, target, ntarget));
547 /* If the FTP host runs VMS, we will have to convert the absolute
548 directory path in UNIX notation to absolute directory path in
549 VMS notation as VMS FTP servers do not like UNIX notation of
550 absolute paths. "VMS notation" is [dir.subdir.subsubdir]. */
552 if (con->rs == ST_VMS)
555 char *ntarget = (char *)alloca (strlen (target) + 2);
556 /* We use a converted initial dir, so directories in
557 TARGET will be separated with slashes, something like
558 "/INITIAL/FOLDER/DIR/SUBDIR". Convert that to
559 "[INITIAL.FOLDER.DIR.SUBDIR]". */
560 strcpy (ntarget, target);
561 assert (*ntarget == '/');
563 for (tmpp = ntarget + 1; *tmpp; tmpp++)
568 DEBUGP (("Changed file name to VMS syntax:\n"));
569 DEBUGP ((" Unix: '%s'\n VMS: '%s'\n", target, ntarget));
573 if (!opt.server_response)
574 logprintf (LOG_VERBOSE, "==> CWD %s ... ", target);
575 err = ftp_cwd (&con->rbuf, target);
576 /* FTPRERR, WRITEFAILED, FTPNSFOD */
580 logputs (LOG_VERBOSE, "\n");
581 logputs (LOG_NOTQUIET, _("\
582 Error in server response, closing control connection.\n"));
584 rbuf_uninitialize (&con->rbuf);
588 logputs (LOG_VERBOSE, "\n");
589 logputs (LOG_NOTQUIET,
590 _("Write failed, closing control connection.\n"));
592 rbuf_uninitialize (&con->rbuf);
596 logputs (LOG_VERBOSE, "\n");
597 logprintf (LOG_NOTQUIET, _("No such directory `%s'.\n\n"),
600 rbuf_uninitialize (&con->rbuf);
610 if (!opt.server_response)
611 logputs (LOG_VERBOSE, _("done.\n"));
614 else /* do not CWD */
615 logputs (LOG_VERBOSE, _("==> CWD not required.\n"));
617 if ((cmd & DO_RETR) && restval && *len == 0)
621 if (!opt.server_response)
622 logprintf (LOG_VERBOSE, "==> SIZE %s ... ", u->file);
625 err = ftp_size(&con->rbuf, u->file, len);
631 logputs (LOG_VERBOSE, "\n");
632 logputs (LOG_NOTQUIET, _("\
633 Error in server response, closing control connection.\n"));
635 rbuf_uninitialize (&con->rbuf);
639 /* Everything is OK. */
645 if (!opt.server_response)
646 logputs (LOG_VERBOSE, _("done.\n"));
649 /* If anything is to be retrieved, PORT (or PASV) must be sent. */
650 if (cmd & (DO_LIST | DO_RETR))
652 if (opt.ftp_pasv > 0)
654 ip_address passive_addr;
656 err = ftp_do_pasv (&con->rbuf, &passive_addr, &passive_port);
657 /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */
661 logputs (LOG_VERBOSE, "\n");
662 logputs (LOG_NOTQUIET, _("\
663 Error in server response, closing control connection.\n"));
665 rbuf_uninitialize (&con->rbuf);
669 logputs (LOG_VERBOSE, "\n");
670 logputs (LOG_NOTQUIET,
671 _("Write failed, closing control connection.\n"));
673 rbuf_uninitialize (&con->rbuf);
677 logputs (LOG_VERBOSE, "\n");
678 logputs (LOG_NOTQUIET, _("Cannot initiate PASV transfer.\n"));
681 logputs (LOG_VERBOSE, "\n");
682 logputs (LOG_NOTQUIET, _("Cannot parse PASV response.\n"));
693 DEBUGP (("trying to connect to %s port %d\n",
694 pretty_print_address (&passive_addr),
696 dtsock = connect_to_ip (&passive_addr, passive_port, NULL);
699 int save_errno = errno;
701 rbuf_uninitialize (&con->rbuf);
702 logprintf (LOG_VERBOSE, _("couldn't connect to %s port %hu: %s\n"),
703 pretty_print_address (&passive_addr), passive_port,
704 strerror (save_errno));
705 return CONNECT_ERROR (save_errno);
708 pasv_mode_open = 1; /* Flag to avoid accept port */
709 if (!opt.server_response)
710 logputs (LOG_VERBOSE, _("done. "));
714 if (!pasv_mode_open) /* Try to use a port command if PASV failed */
716 err = ftp_do_port (&con->rbuf, &local_sock);
717 /* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR,
718 LISTENERR), HOSTERR, FTPPORTERR */
722 logputs (LOG_VERBOSE, "\n");
723 logputs (LOG_NOTQUIET, _("\
724 Error in server response, closing control connection.\n"));
728 rbuf_uninitialize (&con->rbuf);
732 logputs (LOG_VERBOSE, "\n");
733 logputs (LOG_NOTQUIET,
734 _("Write failed, closing control connection.\n"));
738 rbuf_uninitialize (&con->rbuf);
742 logputs (LOG_VERBOSE, "\n");
743 logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
747 rbuf_uninitialize (&con->rbuf);
750 case CONPORTERR: case BINDERR: case LISTENERR:
751 /* What now? These problems are local... */
752 logputs (LOG_VERBOSE, "\n");
753 logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"),
760 logputs (LOG_VERBOSE, "\n");
761 logputs (LOG_NOTQUIET, _("Invalid PORT.\n"));
765 rbuf_uninitialize (&con->rbuf);
775 if (!opt.server_response)
776 logputs (LOG_VERBOSE, _("done. "));
778 } /* cmd & (DO_LIST | DO_RETR) */
780 /* Restart if needed. */
781 if (restval && (cmd & DO_RETR))
783 if (!opt.server_response)
784 logprintf (LOG_VERBOSE, "==> REST %ld ... ", restval);
785 err = ftp_rest (&con->rbuf, restval);
787 /* FTPRERR, WRITEFAILED, FTPRESTFAIL */
791 logputs (LOG_VERBOSE, "\n");
792 logputs (LOG_NOTQUIET, _("\
793 Error in server response, closing control connection.\n"));
797 rbuf_uninitialize (&con->rbuf);
801 logputs (LOG_VERBOSE, "\n");
802 logputs (LOG_NOTQUIET,
803 _("Write failed, closing control connection.\n"));
807 rbuf_uninitialize (&con->rbuf);
811 /* If `-c' is specified and the file already existed when
812 Wget was started, it would be a bad idea for us to start
813 downloading it from scratch, effectively truncating it. */
814 if (opt.always_rest && (cmd & NO_TRUNCATE))
816 logprintf (LOG_NOTQUIET,
817 _("\nREST failed; will not truncate `%s'.\n"),
822 rbuf_uninitialize (&con->rbuf);
823 return CONTNOTSUPPORTED;
825 logputs (LOG_VERBOSE, _("\nREST failed, starting from scratch.\n"));
835 if (err != FTPRESTFAIL && !opt.server_response)
836 logputs (LOG_VERBOSE, _("done. "));
837 } /* restval && cmd & DO_RETR */
841 /* If we're in spider mode, don't really retrieve anything. The
842 fact that we got to this point should be proof enough that
843 the file exists, vaguely akin to HTTP's concept of a "HEAD"
850 rbuf_uninitialize (&con->rbuf);
856 if (!opt.server_response)
859 logputs (LOG_VERBOSE, "\n");
860 logprintf (LOG_VERBOSE, "==> RETR %s ... ", u->file);
864 err = ftp_retr (&con->rbuf, u->file);
865 /* FTPRERR, WRITEFAILED, FTPNSFOD */
869 logputs (LOG_VERBOSE, "\n");
870 logputs (LOG_NOTQUIET, _("\
871 Error in server response, closing control connection.\n"));
875 rbuf_uninitialize (&con->rbuf);
879 logputs (LOG_VERBOSE, "\n");
880 logputs (LOG_NOTQUIET,
881 _("Write failed, closing control connection.\n"));
885 rbuf_uninitialize (&con->rbuf);
889 logputs (LOG_VERBOSE, "\n");
890 logprintf (LOG_NOTQUIET, _("No such file `%s'.\n\n"), u->file);
903 if (!opt.server_response)
904 logputs (LOG_VERBOSE, _("done.\n"));
905 expected_bytes = ftp_expected_bytes (ftp_last_respline);
910 if (!opt.server_response)
911 logputs (LOG_VERBOSE, "==> LIST ... ");
912 /* As Maciej W. Rozycki (macro@ds2.pg.gda.pl) says, `LIST'
913 without arguments is better than `LIST .'; confirmed by
915 err = ftp_list (&con->rbuf, NULL);
916 /* FTPRERR, WRITEFAILED */
920 logputs (LOG_VERBOSE, "\n");
921 logputs (LOG_NOTQUIET, _("\
922 Error in server response, closing control connection.\n"));
926 rbuf_uninitialize (&con->rbuf);
930 logputs (LOG_VERBOSE, "\n");
931 logputs (LOG_NOTQUIET,
932 _("Write failed, closing control connection.\n"));
936 rbuf_uninitialize (&con->rbuf);
940 logputs (LOG_VERBOSE, "\n");
941 logprintf (LOG_NOTQUIET, _("No such file or directory `%s'.\n\n"),
954 if (!opt.server_response)
955 logputs (LOG_VERBOSE, _("done.\n"));
956 expected_bytes = ftp_expected_bytes (ftp_last_respline);
957 } /* cmd & DO_LIST */
959 if (!(cmd & (DO_LIST | DO_RETR)) || (opt.spider && !(cmd & DO_LIST)))
962 /* Some FTP servers return the total length of file after REST
963 command, others just return the remaining size. */
964 if (*len && restval && expected_bytes
965 && (expected_bytes == *len - restval))
967 DEBUGP (("Lying FTP server found, adjusting.\n"));
968 expected_bytes = *len;
971 /* If no transmission was required, then everything is OK. */
972 if (!pasv_mode_open) /* we are not using pasive mode so we need
975 /* Open the data transmission socket by calling acceptport(). */
976 err = acceptport (local_sock, &dtsock);
977 /* Possible errors: ACCEPTERR. */
978 if (err == ACCEPTERR)
980 logprintf (LOG_NOTQUIET, "accept: %s\n", strerror (errno));
985 /* Open the file -- if opt.dfp is set, use it instead. */
986 if (!opt.dfp || con->cmd & DO_LIST)
988 mkalldirs (con->target);
990 rotate_backups (con->target);
991 /* #### Is this correct? */
992 chmod (con->target, 0600);
994 fp = fopen (con->target, restval ? "ab" : "wb");
997 logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, strerror (errno));
999 rbuf_uninitialize (&con->rbuf);
1007 extern int global_download_count;
1010 /* Rewind the output document if the download starts over and if
1011 this is the first download. See gethttp() for a longer
1013 if (!restval && global_download_count == 0 && opt.dfp != stdout)
1015 /* This will silently fail for streams that don't correspond
1016 to regular files, but that's OK. */
1018 /* ftruncate is needed because opt.dfp is opened in append
1019 mode if opt.always_rest is set. */
1020 ftruncate (fileno (fp), 0);
1027 logprintf (LOG_VERBOSE, _("Length: %s"), legible (*len));
1029 logprintf (LOG_VERBOSE, _(" [%s to go]"), legible (*len - restval));
1030 logputs (LOG_VERBOSE, "\n");
1031 expected_bytes = *len; /* for get_contents/show_progress */
1033 else if (expected_bytes)
1035 logprintf (LOG_VERBOSE, _("Length: %s"), legible (expected_bytes));
1037 logprintf (LOG_VERBOSE, _(" [%s to go]"),
1038 legible (expected_bytes - restval));
1039 logputs (LOG_VERBOSE, _(" (unauthoritative)\n"));
1042 /* Get the contents of the document. */
1043 res = get_contents (dtsock, fp, len, restval, expected_bytes, &con->rbuf,
1045 tms = time_str (NULL);
1046 tmrate = retr_rate (*len - restval, con->dltime, 0);
1047 /* Close data connection socket. */
1050 /* Close the local file. */
1052 /* Close or flush the file. We have to be careful to check for
1053 error here. Checking the result of fwrite() is not enough --
1054 errors could go unnoticed! */
1056 if (!opt.dfp || con->cmd & DO_LIST)
1057 flush_res = fclose (fp);
1059 flush_res = fflush (fp);
1060 if (flush_res == EOF)
1064 /* If get_contents couldn't write to fp, bail out. */
1067 logprintf (LOG_NOTQUIET, _("%s: %s, closing control connection.\n"),
1068 con->target, strerror (errno));
1070 rbuf_uninitialize (&con->rbuf);
1075 logprintf (LOG_NOTQUIET, _("%s (%s) - Data connection: %s; "),
1076 tms, tmrate, strerror (errno));
1077 if (opt.server_response)
1078 logputs (LOG_ALWAYS, "\n");
1081 /* Get the server to tell us if everything is retrieved. */
1082 err = ftp_response (&con->rbuf, &respline);
1083 /* ...and empty the buffer. */
1084 rbuf_discard (&con->rbuf);
1088 /* The control connection is decidedly closed. Print the time
1089 only if it hasn't already been printed. */
1091 logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
1092 logputs (LOG_NOTQUIET, _("Control connection closed.\n"));
1093 /* If there is an error on the control connection, close it, but
1094 return FTPRETRINT, since there is a possibility that the
1095 whole file was retrieved nevertheless (but that is for
1096 ftp_loop_internal to decide). */
1098 rbuf_uninitialize (&con->rbuf);
1100 } /* err != FTPOK */
1101 /* If retrieval failed for any reason, return FTPRETRINT, but do not
1102 close socket, since the control connection is still alive. If
1103 there is something wrong with the control connection, it will
1104 become apparent later. */
1105 if (*respline != '2')
1109 logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
1110 logputs (LOG_NOTQUIET, _("Data transfer aborted.\n"));
1117 /* What now? The data connection was erroneous, whereas the
1118 response says everything is OK. We shall play it safe. */
1122 if (!(cmd & LEAVE_PENDING))
1124 /* I should probably send 'QUIT' and check for a reply, but this
1125 is faster. #### Is it OK, though? */
1127 rbuf_uninitialize (&con->rbuf);
1129 /* If it was a listing, and opt.server_response is true,
1131 if (opt.server_response && (con->cmd & DO_LIST))
1133 mkalldirs (con->target);
1134 fp = fopen (con->target, "r");
1136 logprintf (LOG_ALWAYS, "%s: %s\n", con->target, strerror (errno));
1140 /* The lines are being read with read_whole_line because of
1141 no-buffering on opt.lfile. */
1142 while ((line = read_whole_line (fp)))
1144 logprintf (LOG_ALWAYS, "%s\n", line);
1149 } /* con->cmd & DO_LIST && server_response */
1151 return RETRFINISHED;
1154 /* A one-file FTP loop. This is the part where FTP retrieval is
1155 retried, and retried, and retried, and...
1157 This loop either gets commands from con, or (if ON_YOUR_OWN is
1158 set), makes them up to retrieve the file given by the URL. */
1160 ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con)
1165 char *tmrate = NULL;
1170 con->target = url_file_name (u);
1172 if (opt.noclobber && file_exists_p (con->target))
1174 logprintf (LOG_VERBOSE,
1175 _("File `%s' already there, not retrieving.\n"), con->target);
1176 /* If the file is there, we suppose it's retrieved OK. */
1180 /* Remove it if it's a link. */
1181 remove_link (con->target);
1182 if (!opt.output_document)
1185 locf = opt.output_document;
1189 if (con->st & ON_YOUR_OWN)
1190 con->st = ON_YOUR_OWN;
1192 orig_lp = con->cmd & LEAVE_PENDING ? 1 : 0;
1197 /* Increment the pass counter. */
1199 sleep_between_retrievals (count);
1200 if (con->st & ON_YOUR_OWN)
1203 con->cmd |= (DO_RETR | LEAVE_PENDING);
1204 if (rbuf_initialized_p (&con->rbuf))
1205 con->cmd &= ~ (DO_LOGIN | DO_CWD);
1207 con->cmd |= (DO_LOGIN | DO_CWD);
1209 else /* not on your own */
1211 if (rbuf_initialized_p (&con->rbuf))
1212 con->cmd &= ~DO_LOGIN;
1214 con->cmd |= DO_LOGIN;
1215 if (con->st & DONE_CWD)
1216 con->cmd &= ~DO_CWD;
1221 /* Assume no restarting. */
1223 if ((count > 1 || opt.always_rest)
1224 && !(con->cmd & DO_LIST)
1225 && file_exists_p (locf))
1226 if (stat (locf, &st) == 0 && S_ISREG (st.st_mode))
1227 restval = st.st_size;
1229 /* In `-c' is used, check whether the file we're writing to
1230 exists and is of non-zero length. If so, we'll refuse to
1231 truncate it if the server doesn't support continued
1233 if (opt.always_rest && restval > 0)
1234 con->cmd |= NO_TRUNCATE;
1236 /* Get the current time string. */
1237 tms = time_str (NULL);
1238 /* Print fetch message, if opt.verbose. */
1241 char *hurl = url_string (u, 1);
1245 sprintf (tmp, _("(try:%2d)"), count);
1246 logprintf (LOG_VERBOSE, "--%s-- %s\n %s => `%s'\n",
1247 tms, hurl, tmp, locf);
1249 ws_changetitle (hurl, 1);
1253 /* Send getftp the proper length, if fileinfo was provided. */
1258 err = getftp (u, &len, restval, con);
1260 if (!rbuf_initialized_p (&con->rbuf))
1261 con->st &= ~DONE_CWD;
1263 con->st |= DONE_CWD;
1267 case HOSTERR: case CONIMPOSSIBLE: case FWRITEERR: case FOPENERR:
1268 case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case CONTNOTSUPPORTED:
1269 /* Fatal errors, give up. */
1272 case CONSOCKERR: case CONERROR: case FTPSRVERR: case FTPRERR:
1273 case WRITEFAILED: case FTPUNKNOWNTYPE: case CONPORTERR:
1274 case BINDERR: case LISTENERR: case ACCEPTERR:
1275 case FTPPORTERR: case FTPLOGREFUSED: case FTPINVPASV:
1276 printwhat (count, opt.ntry);
1277 /* non-fatal errors */
1281 /* If the control connection was closed, the retrieval
1282 will be considered OK if f->size == len. */
1283 if (!f || len != f->size)
1285 printwhat (count, opt.ntry);
1297 tms = time_str (NULL);
1299 tmrate = retr_rate (len - restval, con->dltime, 0);
1301 /* If we get out of the switch above without continue'ing, we've
1302 successfully downloaded a file. Remember this fact. */
1303 downloaded_file (FILE_DOWNLOADED_NORMALLY, locf);
1305 if (con->st & ON_YOUR_OWN)
1307 CLOSE (RBUF_FD (&con->rbuf));
1308 rbuf_uninitialize (&con->rbuf);
1311 logprintf (LOG_VERBOSE, _("%s (%s) - `%s' saved [%ld]\n\n"),
1312 tms, tmrate, locf, len);
1313 if (!opt.verbose && !opt.quiet)
1315 /* Need to hide the password from the URL. The `if' is here
1316 so that we don't do the needless allocation every
1318 char *hurl = url_string (u, 1);
1319 logprintf (LOG_NONVERBOSE, "%s URL: %s [%ld] -> \"%s\" [%d]\n",
1320 tms, hurl, len, locf, count);
1324 if ((con->cmd & DO_LIST))
1325 /* This is a directory listing file. */
1327 if (!opt.remove_listing)
1328 /* --dont-remove-listing was specified, so do count this towards the
1329 number of bytes and files downloaded. */
1331 total_downloaded_bytes += len;
1335 /* Deletion of listing files is not controlled by --delete-after, but
1336 by the more specific option --dont-remove-listing, and the code
1337 to do this deletion is in another function. */
1339 else if (!opt.spider)
1340 /* This is not a directory listing file. */
1342 /* Unlike directory listing files, don't pretend normal files weren't
1343 downloaded if they're going to be deleted. People seeding proxies,
1344 for instance, may want to know how many bytes and files they've
1345 downloaded through it. */
1346 total_downloaded_bytes += len;
1349 if (opt.delete_after)
1351 DEBUGP (("Removing file due to --delete-after in"
1352 " ftp_loop_internal():\n"));
1353 logprintf (LOG_VERBOSE, _("Removing %s.\n"), locf);
1355 logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1359 /* Restore the original leave-pendingness. */
1361 con->cmd |= LEAVE_PENDING;
1363 con->cmd &= ~LEAVE_PENDING;
1365 } while (!opt.ntry || (count < opt.ntry));
1367 if (rbuf_initialized_p (&con->rbuf) && (con->st & ON_YOUR_OWN))
1369 CLOSE (RBUF_FD (&con->rbuf));
1370 rbuf_uninitialize (&con->rbuf);
1375 /* Return the directory listing in a reusable format. The directory
1376 is specifed in u->dir. */
1378 ftp_get_listing (struct url *u, ccon *con, struct fileinfo **f)
1381 char *uf; /* url file name */
1382 char *lf; /* list file name */
1383 char *old_target = con->target;
1385 con->st &= ~ON_YOUR_OWN;
1386 con->cmd |= (DO_LIST | LEAVE_PENDING);
1387 con->cmd &= ~DO_RETR;
1389 /* Find the listing file name. We do it by taking the file name of
1390 the URL and replacing the last component with the listing file
1392 uf = url_file_name (u);
1393 lf = file_merge (uf, LIST_FILENAME);
1395 DEBUGP ((_("Using `%s' as listing tmp file.\n"), lf));
1398 err = ftp_loop_internal (u, NULL, con);
1399 con->target = old_target;
1402 *f = ftp_parse_ls (lf, con->rs);
1405 if (opt.remove_listing)
1408 logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1410 logprintf (LOG_VERBOSE, _("Removed `%s'.\n"), lf);
1413 con->cmd &= ~DO_LIST;
1417 static uerr_t ftp_retrieve_dirs PARAMS ((struct url *, struct fileinfo *,
1419 static uerr_t ftp_retrieve_glob PARAMS ((struct url *, ccon *, int));
1420 static struct fileinfo *delelement PARAMS ((struct fileinfo *,
1421 struct fileinfo **));
1422 static void freefileinfo PARAMS ((struct fileinfo *f));
1424 /* Retrieve a list of files given in struct fileinfo linked list. If
1425 a file is a symbolic link, do not retrieve it, but rather try to
1426 set up a similar link on the local disk, if the symlinks are
1429 If opt.recursive is set, after all files have been retrieved,
1430 ftp_retrieve_dirs will be called to retrieve the directories. */
1432 ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con)
1434 static int depth = 0;
1436 struct fileinfo *orig;
1441 /* Increase the depth. */
1443 if (opt.reclevel != INFINITE_RECURSION && depth > opt.reclevel)
1445 DEBUGP ((_("Recursion depth %d exceeded max. depth %d.\n"),
1446 depth, opt.reclevel));
1454 con->st &= ~ON_YOUR_OWN;
1455 if (!(con->st & DONE_CWD))
1458 con->cmd &= ~DO_CWD;
1459 con->cmd |= (DO_RETR | LEAVE_PENDING);
1461 if (!rbuf_initialized_p (&con->rbuf))
1462 con->cmd |= DO_LOGIN;
1464 con->cmd &= ~DO_LOGIN;
1466 err = RETROK; /* in case it's not used */
1470 char *old_target, *ofile;
1472 if (opt.quota && total_downloaded_bytes > opt.quota)
1477 old_target = con->target;
1479 ofile = xstrdup (u->file);
1480 url_set_file (u, f->name);
1482 con->target = url_file_name (u);
1486 if (opt.timestamping && f->type == FT_PLAINFILE)
1489 /* If conversion of HTML files retrieved via FTP is ever implemented,
1490 we'll need to stat() <file>.orig here when -K has been specified.
1491 I'm not implementing it now since files on an FTP server are much
1492 more likely than files on an HTTP server to legitimately have a
1494 if (!stat (con->target, &st))
1498 /* Else, get it from the file. */
1499 local_size = st.st_size;
1502 /* Modification time granularity is 2 seconds for Windows, so
1503 increase local time by 1 second for later comparison. */
1506 /* Compare file sizes only for servers that tell us correct
1507 values. Assumme sizes being equal for servers that lie
1509 cor_val = (con->rs == ST_UNIX || con->rs == ST_WINNT);
1510 eq_size = cor_val ? (local_size == f->size) : 1 ;
1511 if (f->tstamp <= tml && eq_size)
1513 /* Remote file is older, file sizes can be compared and
1515 logprintf (LOG_VERBOSE, _("\
1516 Remote file no newer than local file `%s' -- not retrieving.\n"), con->target);
1521 /* Remote file is newer or sizes cannot be matched */
1522 logprintf (LOG_VERBOSE, _("\
1523 Remote file is newer than local file `%s' -- retrieving.\n\n"),
1528 /* Sizes do not match */
1529 logprintf (LOG_VERBOSE, _("\
1530 The sizes do not match (local %ld) -- retrieving.\n\n"), local_size);
1533 } /* opt.timestamping && f->type == FT_PLAINFILE */
1537 /* If opt.retr_symlinks is defined, we treat symlinks as
1538 if they were normal files. There is currently no way
1539 to distinguish whether they might be directories, and
1541 if (!opt.retr_symlinks)
1545 logputs (LOG_NOTQUIET,
1546 _("Invalid name of the symlink, skipping.\n"));
1550 /* Check whether we already have the correct
1552 int rc = lstat (con->target, &st);
1555 size_t len = strlen (f->linkto) + 1;
1556 if (S_ISLNK (st.st_mode))
1558 char *link_target = (char *)alloca (len);
1559 size_t n = readlink (con->target, link_target, len);
1561 && (memcmp (link_target, f->linkto, n) == 0))
1563 logprintf (LOG_VERBOSE, _("\
1564 Already have correct symlink %s -> %s\n\n"),
1565 con->target, f->linkto);
1571 logprintf (LOG_VERBOSE, _("Creating symlink %s -> %s\n"),
1572 con->target, f->linkto);
1573 /* Unlink before creating symlink! */
1574 unlink (con->target);
1575 if (symlink (f->linkto, con->target) == -1)
1576 logprintf (LOG_NOTQUIET, "symlink: %s\n",
1578 logputs (LOG_VERBOSE, "\n");
1579 } /* have f->linkto */
1580 #else /* not HAVE_SYMLINK */
1581 logprintf (LOG_NOTQUIET,
1582 _("Symlinks not supported, skipping symlink `%s'.\n"),
1584 #endif /* not HAVE_SYMLINK */
1586 else /* opt.retr_symlinks */
1589 err = ftp_loop_internal (u, f, con);
1590 } /* opt.retr_symlinks */
1594 logprintf (LOG_NOTQUIET, _("Skipping directory `%s'.\n"),
1598 /* Call the retrieve loop. */
1600 err = ftp_loop_internal (u, f, con);
1603 logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"),
1608 /* Set the time-stamp information to the local file. Symlinks
1609 are not to be stamped because it sets the stamp on the
1611 if (!(f->type == FT_SYMLINK && !opt.retr_symlinks)
1614 && file_exists_p (con->target))
1616 /* #### This code repeats in http.c and ftp.c. Move it to a
1618 const char *fl = NULL;
1619 if (opt.output_document)
1621 if (opt.od_known_regular)
1622 fl = opt.output_document;
1627 touch (fl, f->tstamp);
1629 else if (f->tstamp == -1)
1630 logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"), con->target);
1632 if (f->perms && f->type == FT_PLAINFILE && dlthis)
1633 chmod (con->target, f->perms);
1635 DEBUGP (("Unrecognized permissions for %s.\n", con->target));
1637 xfree (con->target);
1638 con->target = old_target;
1640 url_set_file (u, ofile);
1643 /* Break on fatals. */
1644 if (err == QUOTEXC || err == HOSTERR || err == FWRITEERR)
1646 con->cmd &= ~ (DO_CWD | DO_LOGIN);
1650 /* We do not want to call ftp_retrieve_dirs here */
1651 if (opt.recursive &&
1652 !(opt.reclevel != INFINITE_RECURSION && depth >= opt.reclevel))
1653 err = ftp_retrieve_dirs (u, orig, con);
1654 else if (opt.recursive)
1655 DEBUGP ((_("Will not retrieve dirs since depth is %d (max %d).\n"),
1656 depth, opt.reclevel));
1661 /* Retrieve the directories given in a file list. This function works
1662 by simply going through the linked list and calling
1663 ftp_retrieve_glob on each directory entry. The function knows
1664 about excluded directories. */
1666 ftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con)
1668 char *container = NULL;
1669 int container_size = 0;
1671 for (; f; f = f->next)
1674 char *odir, *newdir;
1676 if (opt.quota && total_downloaded_bytes > opt.quota)
1678 if (f->type != FT_DIRECTORY)
1681 /* Allocate u->dir off stack, but reallocate only if a larger
1682 string is needed. It's a pity there's no "realloca" for an
1683 item on the bottom of the stack. */
1684 size = strlen (u->dir) + 1 + strlen (f->name) + 1;
1685 if (size > container_size)
1686 container = (char *)alloca (size);
1691 || (*odir == '/' && *(odir + 1) == '\0'))
1692 /* If ODIR is empty or just "/", simply append f->name to
1693 ODIR. (In the former case, to preserve u->dir being
1694 relative; in the latter case, to avoid double slash.) */
1695 sprintf (newdir, "%s%s", odir, f->name);
1697 /* Else, use a separator. */
1698 sprintf (newdir, "%s/%s", odir, f->name);
1700 DEBUGP (("Composing new CWD relative to the initial directory.\n"));
1701 DEBUGP ((" odir = '%s'\n f->name = '%s'\n newdir = '%s'\n\n",
1702 odir, f->name, newdir));
1703 if (!accdir (newdir, ALLABS))
1705 logprintf (LOG_VERBOSE, _("\
1706 Not descending to `%s' as it is excluded/not-included.\n"), newdir);
1710 con->st &= ~DONE_CWD;
1712 odir = xstrdup (u->dir); /* because url_set_dir will free
1714 url_set_dir (u, newdir);
1715 ftp_retrieve_glob (u, con, GETALL);
1716 url_set_dir (u, odir);
1719 /* Set the time-stamp? */
1722 if (opt.quota && total_downloaded_bytes > opt.quota)
1728 /* Return non-zero if S has a leading '/' or contains '../' */
1730 has_insecure_name_p (const char *s)
1735 if (strstr(s, "../") != 0)
1741 /* A near-top-level function to retrieve the files in a directory.
1742 The function calls ftp_get_listing, to get a linked list of files.
1743 Then it weeds out the file names that do not match the pattern.
1744 ftp_retrieve_list is called with this updated list as an argument.
1746 If the argument ACTION is GETONE, just download the file (but first
1747 get the listing, so that the time-stamp is heeded); if it's GLOBALL,
1748 use globbing; if it's GETALL, download the whole directory. */
1750 ftp_retrieve_glob (struct url *u, ccon *con, int action)
1752 struct fileinfo *f, *start;
1755 con->cmd |= LEAVE_PENDING;
1757 res = ftp_get_listing (u, con, &start);
1760 /* First: weed out that do not conform the global rules given in
1761 opt.accepts and opt.rejects. */
1762 if (opt.accepts || opt.rejects)
1767 if (f->type != FT_DIRECTORY && !acceptable (f->name))
1769 logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"), f->name);
1770 f = delelement (f, &start);
1776 /* Remove all files with possible harmful names */
1780 if (has_insecure_name_p (f->name))
1782 logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"), f->name);
1783 f = delelement (f, &start);
1788 /* Now weed out the files that do not match our globbing pattern.
1789 If we are dealing with a globbing pattern, that is. */
1790 if (*u->file && (action == GLOBALL || action == GETONE))
1797 matchres = fnmatch (u->file, f->name, 0);
1800 logprintf (LOG_NOTQUIET, "%s: %s\n", con->target,
1804 if (matchres == FNM_NOMATCH)
1805 f = delelement (f, &start); /* delete the element from the list */
1807 f = f->next; /* leave the element in the list */
1811 freefileinfo (start);
1812 return RETRBADPATTERN;
1818 /* Just get everything. */
1819 ftp_retrieve_list (u, start, con);
1823 if (action == GLOBALL)
1826 /* #### This message SUCKS. We should see what was the
1827 reason that nothing was retrieved. */
1828 logprintf (LOG_VERBOSE, _("No matches on pattern `%s'.\n"), u->file);
1830 else /* GETONE or GETALL */
1832 /* Let's try retrieving it anyway. */
1833 con->st |= ON_YOUR_OWN;
1834 res = ftp_loop_internal (u, NULL, con);
1838 freefileinfo (start);
1839 if (opt.quota && total_downloaded_bytes > opt.quota)
1842 /* #### Should we return `res' here? */
1846 /* The wrapper that calls an appropriate routine according to contents
1847 of URL. Inherently, its capabilities are limited on what can be
1848 encoded into a URL. */
1850 ftp_loop (struct url *u, int *dt, struct url *proxy)
1852 ccon con; /* FTP connection */
1857 memset (&con, 0, sizeof (con));
1859 rbuf_uninitialize (&con.rbuf);
1860 con.st = ON_YOUR_OWN;
1864 res = RETROK; /* in case it's not used */
1866 /* If the file name is empty, the user probably wants a directory
1867 index. We'll provide one, properly HTML-ized. Unless
1868 opt.htmlify is 0, of course. :-) */
1869 if (!*u->file && !opt.recursive)
1872 res = ftp_get_listing (u, &con, &f);
1876 if (opt.htmlify && !opt.spider)
1878 char *filename = (opt.output_document
1879 ? xstrdup (opt.output_document)
1880 : (con.target ? xstrdup (con.target)
1881 : url_file_name (u)));
1882 res = ftp_index (filename, u, f);
1883 if (res == FTPOK && opt.verbose)
1885 if (!opt.output_document)
1889 if (stat (filename, &st) == 0)
1893 logprintf (LOG_NOTQUIET,
1894 _("Wrote HTML-ized index to `%s' [%ld].\n"),
1898 logprintf (LOG_NOTQUIET,
1899 _("Wrote HTML-ized index to `%s'.\n"),
1909 int wild = has_wildcards_p (u->file);
1910 if ((opt.ftp_glob && wild) || opt.recursive || opt.timestamping)
1912 /* ftp_retrieve_glob is a catch-all function that gets called
1913 if we need globbing, time-stamping or recursion. Its
1914 third argument is just what we really need. */
1915 res = ftp_retrieve_glob (u, &con,
1916 (opt.ftp_glob && wild) ? GLOBALL : GETONE);
1919 res = ftp_loop_internal (u, NULL, &con);
1925 /* If a connection was left, quench it. */
1926 if (rbuf_initialized_p (&con.rbuf))
1927 CLOSE (RBUF_FD (&con.rbuf));
1928 xfree_null (con.id);
1930 xfree_null (con.target);
1935 /* Delete an element from the fileinfo linked list. Returns the
1936 address of the next element, or NULL if the list is exhausted. It
1937 can modify the start of the list. */
1938 static struct fileinfo *
1939 delelement (struct fileinfo *f, struct fileinfo **start)
1941 struct fileinfo *prev = f->prev;
1942 struct fileinfo *next = f->next;
1945 xfree_null (f->linkto);
1957 /* Free the fileinfo linked list of files. */
1959 freefileinfo (struct fileinfo *f)
1963 struct fileinfo *next = f->next;