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 */
62 extern LARGE_INT total_downloaded_bytes;
64 /* File where the "ls -al" listing will be saved. */
65 #define LIST_FILENAME ".listing"
67 extern char ftp_last_respline[];
71 int st; /* connection status */
72 int cmd; /* command code */
73 struct rbuf rbuf; /* control connection buffer */
74 double dltime; /* time of the download in msecs */
75 enum stype rs; /* remote system reported by ftp server */
76 char *id; /* initial directory */
77 char *target; /* target file name */
78 struct url *proxy; /* FTWK-style proxy */
82 /* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in
83 the string S, and return the number converted to long, if found, 0
86 ftp_expected_bytes (const char *s)
92 while (*s && *s != '(')
96 for (++s; *s && ISSPACE (*s); s++);
104 res = (*s - '0') + 10 * res;
107 while (*s && ISDIGIT (*s));
110 while (*s && ISSPACE (*s))
114 if (TOLOWER (*s) != 'b')
116 if (strncasecmp (s, "byte", 4))
128 struct sockaddr_storage ss;
129 struct sockaddr *sa = (struct sockaddr *)&ss;
130 socklen_t len = sizeof (ss);
134 if (getpeername (fd, sa, &len) < 0)
135 /* Mauro Tortonesi: HOW DO WE HANDLE THIS ERROR? */
138 return sa->sa_family;
142 * This function sets up a passive data connection with the FTP server.
143 * It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv.
146 ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
151 family = getfamily (rbuf->fd);
152 assert (family == AF_INET || family == AF_INET6);
154 /* If our control connection is over IPv6, then we first try EPSV and then
155 * LPSV if the former is not supported. If the control connection is over
156 * IPv4, we simply issue the good old PASV request. */
157 if (family == AF_INET6)
159 if (!opt.server_response)
160 logputs (LOG_VERBOSE, "==> EPSV ... ");
161 err = ftp_epsv (rbuf, addr, port);
163 /* If EPSV is not supported try LPSV */
164 if (err == FTPNOPASV)
166 if (!opt.server_response)
167 logputs (LOG_VERBOSE, "==> LPSV ... ");
168 err = ftp_lpsv (rbuf, addr, port);
173 if (!opt.server_response)
174 logputs (LOG_VERBOSE, "==> PASV ... ");
175 err = ftp_pasv (rbuf, addr, port);
182 * This function sets up an active data connection with the FTP server.
183 * It is merely a wrapper around ftp_eprt, ftp_lprt and ftp_port.
186 ftp_do_port (struct rbuf *rbuf)
191 assert (rbuf != NULL);
192 assert (rbuf_initialized_p (rbuf));
194 family = getfamily (rbuf->fd);
195 assert (family == AF_INET || family == AF_INET6);
197 /* If our control connection is over IPv6, then we first try EPRT and then
198 * LPRT if the former is not supported. If the control connection is over
199 * IPv4, we simply issue the good old PORT request. */
200 if (family == AF_INET6)
202 if (!opt.server_response)
203 logputs (LOG_VERBOSE, "==> EPRT ... ");
204 err = ftp_eprt (rbuf);
206 /* If EPRT is not supported try LPRT */
207 if (err == FTPPORTERR)
209 if (!opt.server_response)
210 logputs (LOG_VERBOSE, "==> LPRT ... ");
211 err = ftp_lprt (rbuf);
216 if (!opt.server_response)
217 logputs (LOG_VERBOSE, "==> PORT ... ");
218 err = ftp_port (rbuf);
224 #define ftp_do_pasv ftp_pasv
225 #define ftp_do_port ftp_port
228 /* Retrieves a file with denoted parameters through opening an FTP
229 connection to the server. It always closes the data connection,
230 and closes the control connection in case of error. */
232 getftp (struct url *u, long *len, long restval, ccon *con)
234 int csock, dtsock, res;
237 char *user, *passwd, *respline;
240 int pasv_mode_open = 0;
241 long expected_bytes = 0L;
243 assert (con != NULL);
244 assert (con->target != NULL);
246 /* Debug-check of the sanity of the request by making sure that LIST
247 and RETR are never both requested (since we can handle only one
249 assert (!((cmd & DO_LIST) && (cmd & DO_RETR)));
250 /* Make sure that at least *something* is requested. */
251 assert ((cmd & (DO_LIST | DO_CWD | DO_RETR | DO_LOGIN)) != 0);
255 search_netrc (u->host, (const char **)&user, (const char **)&passwd, 1);
256 user = user ? user : opt.ftp_acc;
257 passwd = passwd ? passwd : opt.ftp_pass;
258 assert (user && passwd);
263 if (!(cmd & DO_LOGIN))
264 csock = RBUF_FD (&con->rbuf);
265 else /* cmd & DO_LOGIN */
268 struct address_list *al;
270 char *host = con->proxy ? con->proxy->host : u->host;
271 int port = con->proxy ? con->proxy->port : u->port;
272 char *logname = user;
276 /* If proxy is in use, log in as username@target-site. */
277 logname = xmalloc (strlen (user) + 1 + strlen (u->host) + 1);
278 sprintf (logname, "%s@%s", user, u->host);
281 /* Login to the server: */
283 /* First: Establish the control connection. */
285 al = lookup_host (host, 0);
288 set_connection_host_name (host);
289 csock = connect_to_many (al, port, 0);
290 set_connection_host_name (NULL);
291 address_list_release (al);
294 return CONNECT_ERROR (errno);
296 if (cmd & LEAVE_PENDING)
297 rbuf_initialize (&con->rbuf, csock);
299 rbuf_uninitialize (&con->rbuf);
301 /* Since this is a new connection, we may safely discard
302 anything left in the buffer. */
303 rbuf_discard (&con->rbuf);
305 /* Second: Login with proper USER/PASS sequence. */
306 logprintf (LOG_VERBOSE, _("Logging in as %s ... "), user);
307 if (opt.server_response)
308 logputs (LOG_ALWAYS, "\n");
309 err = ftp_login (&con->rbuf, logname, passwd);
314 /* FTPRERR, FTPSRVERR, WRITEFAILED, FTPLOGREFUSED, FTPLOGINC */
318 logputs (LOG_VERBOSE, "\n");
319 logputs (LOG_NOTQUIET, _("\
320 Error in server response, closing control connection.\n"));
322 rbuf_uninitialize (&con->rbuf);
326 logputs (LOG_VERBOSE, "\n");
327 logputs (LOG_NOTQUIET, _("Error in server greeting.\n"));
329 rbuf_uninitialize (&con->rbuf);
333 logputs (LOG_VERBOSE, "\n");
334 logputs (LOG_NOTQUIET,
335 _("Write failed, closing control connection.\n"));
337 rbuf_uninitialize (&con->rbuf);
341 logputs (LOG_VERBOSE, "\n");
342 logputs (LOG_NOTQUIET, _("The server refuses login.\n"));
344 rbuf_uninitialize (&con->rbuf);
345 return FTPLOGREFUSED;
348 logputs (LOG_VERBOSE, "\n");
349 logputs (LOG_NOTQUIET, _("Login incorrect.\n"));
351 rbuf_uninitialize (&con->rbuf);
355 if (!opt.server_response)
356 logputs (LOG_VERBOSE, _("Logged in!\n"));
363 /* Third: Get the system type */
364 if (!opt.server_response)
365 logprintf (LOG_VERBOSE, "==> SYST ... ");
366 err = ftp_syst (&con->rbuf, &con->rs);
371 logputs (LOG_VERBOSE, "\n");
372 logputs (LOG_NOTQUIET, _("\
373 Error in server response, closing control connection.\n"));
375 rbuf_uninitialize (&con->rbuf);
379 logputs (LOG_VERBOSE, "\n");
380 logputs (LOG_NOTQUIET,
381 _("Server error, can't determine system type.\n"));
384 /* Everything is OK. */
390 if (!opt.server_response && err != FTPSRVERR)
391 logputs (LOG_VERBOSE, _("done. "));
393 /* Fourth: Find the initial ftp directory */
395 if (!opt.server_response)
396 logprintf (LOG_VERBOSE, "==> PWD ... ");
397 err = ftp_pwd(&con->rbuf, &con->id);
402 logputs (LOG_VERBOSE, "\n");
403 logputs (LOG_NOTQUIET, _("\
404 Error in server response, closing control connection.\n"));
406 rbuf_uninitialize (&con->rbuf);
410 /* PWD unsupported -- assume "/". */
411 FREE_MAYBE (con->id);
412 con->id = xstrdup ("/");
415 /* Everything is OK. */
421 /* VMS will report something like "PUB$DEVICE:[INITIAL.FOLDER]".
422 Convert it to "/INITIAL/FOLDER" */
423 if (con->rs == ST_VMS)
425 char *path = strchr (con->id, '[');
426 char *pathend = path ? strchr (path + 1, ']') : NULL;
427 if (!path || !pathend)
428 DEBUGP (("Initial VMS directory not in the form [...]!\n"));
431 char *idir = con->id;
432 DEBUGP (("Preprocessing the initial VMS directory\n"));
433 DEBUGP ((" old = '%s'\n", con->id));
434 /* We do the conversion in-place by copying the stuff
435 between [ and ] to the beginning, and changing dots
436 to slashes at the same time. */
438 for (++path; path < pathend; path++, idir++)
439 *idir = *path == '.' ? '/' : *path;
441 DEBUGP ((" new = '%s'\n\n", con->id));
444 if (!opt.server_response)
445 logputs (LOG_VERBOSE, _("done.\n"));
447 /* Fifth: Set the FTP type. */
448 type_char = ftp_process_type (u->params);
449 if (!opt.server_response)
450 logprintf (LOG_VERBOSE, "==> TYPE %c ... ", type_char);
451 err = ftp_type (&con->rbuf, type_char);
452 /* FTPRERR, WRITEFAILED, FTPUNKNOWNTYPE */
456 logputs (LOG_VERBOSE, "\n");
457 logputs (LOG_NOTQUIET, _("\
458 Error in server response, closing control connection.\n"));
460 rbuf_uninitialize (&con->rbuf);
464 logputs (LOG_VERBOSE, "\n");
465 logputs (LOG_NOTQUIET,
466 _("Write failed, closing control connection.\n"));
468 rbuf_uninitialize (&con->rbuf);
472 logputs (LOG_VERBOSE, "\n");
473 logprintf (LOG_NOTQUIET,
474 _("Unknown type `%c', closing control connection.\n"),
477 rbuf_uninitialize (&con->rbuf);
480 /* Everything is OK. */
486 if (!opt.server_response)
487 logputs (LOG_VERBOSE, _("done. "));
493 logputs (LOG_VERBOSE, _("==> CWD not needed.\n"));
496 char *target = u->dir;
498 DEBUGP (("changing working directory\n"));
500 /* Change working directory. To change to a non-absolute
501 Unix directory, we need to prepend initial directory
502 (con->id) to it. Absolute directories "just work".
504 A relative directory is one that does not begin with '/'
505 and, on non-Unix OS'es, one that doesn't begin with
508 This is not done for OS400, which doesn't use
509 "/"-delimited directories, nor does it support directory
510 hierarchies. "CWD foo" followed by "CWD bar" leaves us
511 in "bar", not in "foo/bar", as would be customary
515 && !(con->rs != ST_UNIX
516 && ISALPHA (target[0])
518 && con->rs != ST_OS400)
520 int idlen = strlen (con->id);
523 /* Strip trailing slash(es) from con->id. */
524 while (idlen > 0 && con->id[idlen - 1] == '/')
526 p = ntarget = (char *)alloca (idlen + 1 + strlen (u->dir) + 1);
527 memcpy (p, con->id, idlen);
532 DEBUGP (("Prepended initial PWD to relative path:\n"));
533 DEBUGP ((" pwd: '%s'\n old: '%s'\n new: '%s'\n",
534 con->id, target, ntarget));
538 /* If the FTP host runs VMS, we will have to convert the absolute
539 directory path in UNIX notation to absolute directory path in
540 VMS notation as VMS FTP servers do not like UNIX notation of
541 absolute paths. "VMS notation" is [dir.subdir.subsubdir]. */
543 if (con->rs == ST_VMS)
546 char *ntarget = (char *)alloca (strlen (target) + 2);
547 /* We use a converted initial dir, so directories in
548 TARGET will be separated with slashes, something like
549 "/INITIAL/FOLDER/DIR/SUBDIR". Convert that to
550 "[INITIAL.FOLDER.DIR.SUBDIR]". */
551 strcpy (ntarget, target);
552 assert (*ntarget == '/');
554 for (tmpp = ntarget + 1; *tmpp; tmpp++)
559 DEBUGP (("Changed file name to VMS syntax:\n"));
560 DEBUGP ((" Unix: '%s'\n VMS: '%s'\n", target, ntarget));
564 if (!opt.server_response)
565 logprintf (LOG_VERBOSE, "==> CWD %s ... ", target);
566 err = ftp_cwd (&con->rbuf, target);
567 /* FTPRERR, WRITEFAILED, FTPNSFOD */
571 logputs (LOG_VERBOSE, "\n");
572 logputs (LOG_NOTQUIET, _("\
573 Error in server response, closing control connection.\n"));
575 rbuf_uninitialize (&con->rbuf);
579 logputs (LOG_VERBOSE, "\n");
580 logputs (LOG_NOTQUIET,
581 _("Write failed, closing control connection.\n"));
583 rbuf_uninitialize (&con->rbuf);
587 logputs (LOG_VERBOSE, "\n");
588 logprintf (LOG_NOTQUIET, _("No such directory `%s'.\n\n"),
591 rbuf_uninitialize (&con->rbuf);
601 if (!opt.server_response)
602 logputs (LOG_VERBOSE, _("done.\n"));
605 else /* do not CWD */
606 logputs (LOG_VERBOSE, _("==> CWD not required.\n"));
608 if ((cmd & DO_RETR) && restval && *len == 0)
612 if (!opt.server_response)
613 logprintf (LOG_VERBOSE, "==> SIZE %s ... ", u->file);
616 err = ftp_size(&con->rbuf, u->file, len);
622 logputs (LOG_VERBOSE, "\n");
623 logputs (LOG_NOTQUIET, _("\
624 Error in server response, closing control connection.\n"));
626 rbuf_uninitialize (&con->rbuf);
630 /* Everything is OK. */
636 if (!opt.server_response)
637 logputs (LOG_VERBOSE, _("done.\n"));
640 /* If anything is to be retrieved, PORT (or PASV) must be sent. */
641 if (cmd & (DO_LIST | DO_RETR))
643 if (opt.ftp_pasv > 0)
645 ip_address passive_addr;
646 unsigned short passive_port;
647 if (!opt.server_response)
648 logputs (LOG_VERBOSE, "==> PASV ... ");
649 err = ftp_do_pasv (&con->rbuf, &passive_addr, &passive_port);
650 /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */
654 logputs (LOG_VERBOSE, "\n");
655 logputs (LOG_NOTQUIET, _("\
656 Error in server response, closing control connection.\n"));
658 rbuf_uninitialize (&con->rbuf);
662 logputs (LOG_VERBOSE, "\n");
663 logputs (LOG_NOTQUIET,
664 _("Write failed, closing control connection.\n"));
666 rbuf_uninitialize (&con->rbuf);
670 logputs (LOG_VERBOSE, "\n");
671 logputs (LOG_NOTQUIET, _("Cannot initiate PASV transfer.\n"));
674 logputs (LOG_VERBOSE, "\n");
675 logputs (LOG_NOTQUIET, _("Cannot parse PASV response.\n"));
686 DEBUGP (("trying to connect to %s port %d\n",
687 pretty_print_address (&passive_addr),
689 dtsock = connect_to_one (&passive_addr, passive_port, 1);
692 int save_errno = errno;
694 rbuf_uninitialize (&con->rbuf);
695 logprintf (LOG_VERBOSE, _("couldn't connect to %s port %hu: %s\n"),
696 pretty_print_address (&passive_addr), passive_port,
697 strerror (save_errno));
698 return CONNECT_ERROR (save_errno);
701 pasv_mode_open = 1; /* Flag to avoid accept port */
702 if (!opt.server_response)
703 logputs (LOG_VERBOSE, _("done. "));
707 if (!pasv_mode_open) /* Try to use a port command if PASV failed */
709 if (!opt.server_response)
710 logputs (LOG_VERBOSE, "==> PORT ... ");
711 err = ftp_do_port (&con->rbuf);
712 /* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR,
713 LISTENERR), HOSTERR, FTPPORTERR */
717 logputs (LOG_VERBOSE, "\n");
718 logputs (LOG_NOTQUIET, _("\
719 Error in server response, closing control connection.\n"));
722 rbuf_uninitialize (&con->rbuf);
726 logputs (LOG_VERBOSE, "\n");
727 logputs (LOG_NOTQUIET,
728 _("Write failed, closing control connection.\n"));
731 rbuf_uninitialize (&con->rbuf);
735 logputs (LOG_VERBOSE, "\n");
736 logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
739 rbuf_uninitialize (&con->rbuf);
742 case CONPORTERR: case BINDERR: case LISTENERR:
743 /* What now? These problems are local... */
744 logputs (LOG_VERBOSE, "\n");
745 logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"),
751 logputs (LOG_VERBOSE, "\n");
752 logputs (LOG_NOTQUIET, _("Invalid PORT.\n"));
755 rbuf_uninitialize (&con->rbuf);
765 if (!opt.server_response)
766 logputs (LOG_VERBOSE, _("done. "));
768 } /* cmd & (DO_LIST | DO_RETR) */
770 /* Restart if needed. */
771 if (restval && (cmd & DO_RETR))
773 if (!opt.server_response)
774 logprintf (LOG_VERBOSE, "==> REST %ld ... ", restval);
775 err = ftp_rest (&con->rbuf, restval);
777 /* FTPRERR, WRITEFAILED, FTPRESTFAIL */
781 logputs (LOG_VERBOSE, "\n");
782 logputs (LOG_NOTQUIET, _("\
783 Error in server response, closing control connection.\n"));
786 rbuf_uninitialize (&con->rbuf);
790 logputs (LOG_VERBOSE, "\n");
791 logputs (LOG_NOTQUIET,
792 _("Write failed, closing control connection.\n"));
795 rbuf_uninitialize (&con->rbuf);
799 /* If `-c' is specified and the file already existed when
800 Wget was started, it would be a bad idea for us to start
801 downloading it from scratch, effectively truncating it. */
802 if (opt.always_rest && (cmd & NO_TRUNCATE))
804 logprintf (LOG_NOTQUIET,
805 _("\nREST failed; will not truncate `%s'.\n"),
809 rbuf_uninitialize (&con->rbuf);
810 return CONTNOTSUPPORTED;
812 logputs (LOG_VERBOSE, _("\nREST failed, starting from scratch.\n"));
822 if (err != FTPRESTFAIL && !opt.server_response)
823 logputs (LOG_VERBOSE, _("done. "));
824 } /* restval && cmd & DO_RETR */
828 /* If we're in spider mode, don't really retrieve anything. The
829 fact that we got to this point should be proof enough that
830 the file exists, vaguely akin to HTTP's concept of a "HEAD"
836 rbuf_uninitialize (&con->rbuf);
842 if (!opt.server_response)
845 logputs (LOG_VERBOSE, "\n");
846 logprintf (LOG_VERBOSE, "==> RETR %s ... ", u->file);
850 err = ftp_retr (&con->rbuf, u->file);
851 /* FTPRERR, WRITEFAILED, FTPNSFOD */
855 logputs (LOG_VERBOSE, "\n");
856 logputs (LOG_NOTQUIET, _("\
857 Error in server response, closing control connection.\n"));
860 rbuf_uninitialize (&con->rbuf);
864 logputs (LOG_VERBOSE, "\n");
865 logputs (LOG_NOTQUIET,
866 _("Write failed, closing control connection.\n"));
869 rbuf_uninitialize (&con->rbuf);
873 logputs (LOG_VERBOSE, "\n");
874 logprintf (LOG_NOTQUIET, _("No such file `%s'.\n\n"), u->file);
886 if (!opt.server_response)
887 logputs (LOG_VERBOSE, _("done.\n"));
888 expected_bytes = ftp_expected_bytes (ftp_last_respline);
893 if (!opt.server_response)
894 logputs (LOG_VERBOSE, "==> LIST ... ");
895 /* As Maciej W. Rozycki (macro@ds2.pg.gda.pl) says, `LIST'
896 without arguments is better than `LIST .'; confirmed by
898 err = ftp_list (&con->rbuf, NULL);
899 /* FTPRERR, WRITEFAILED */
903 logputs (LOG_VERBOSE, "\n");
904 logputs (LOG_NOTQUIET, _("\
905 Error in server response, closing control connection.\n"));
908 rbuf_uninitialize (&con->rbuf);
912 logputs (LOG_VERBOSE, "\n");
913 logputs (LOG_NOTQUIET,
914 _("Write failed, closing control connection.\n"));
917 rbuf_uninitialize (&con->rbuf);
921 logputs (LOG_VERBOSE, "\n");
922 logprintf (LOG_NOTQUIET, _("No such file or directory `%s'.\n\n"),
934 if (!opt.server_response)
935 logputs (LOG_VERBOSE, _("done.\n"));
936 expected_bytes = ftp_expected_bytes (ftp_last_respline);
937 } /* cmd & DO_LIST */
939 if (!(cmd & (DO_LIST | DO_RETR)) || (opt.spider && !(cmd & DO_LIST)))
942 /* Some FTP servers return the total length of file after REST
943 command, others just return the remaining size. */
944 if (*len && restval && expected_bytes
945 && (expected_bytes == *len - restval))
947 DEBUGP (("Lying FTP server found, adjusting.\n"));
948 expected_bytes = *len;
951 /* If no transmission was required, then everything is OK. */
952 if (!pasv_mode_open) /* we are not using pasive mode so we need
955 /* Open the data transmission socket by calling acceptport(). */
956 err = acceptport (&dtsock);
957 /* Possible errors: ACCEPTERR. */
958 if (err == ACCEPTERR)
960 logprintf (LOG_NOTQUIET, "accept: %s\n", strerror (errno));
965 /* Open the file -- if opt.dfp is set, use it instead. */
966 if (!opt.dfp || con->cmd & DO_LIST)
968 mkalldirs (con->target);
970 rotate_backups (con->target);
971 /* #### Is this correct? */
972 chmod (con->target, 0600);
974 fp = fopen (con->target, restval ? "ab" : "wb");
977 logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, strerror (errno));
979 rbuf_uninitialize (&con->rbuf);
986 extern int global_download_count;
989 /* Rewind the output document if the download starts over and if
990 this is the first download. See gethttp() for a longer
992 if (!restval && global_download_count == 0 && opt.dfp != stdout)
994 /* This will silently fail for streams that don't correspond
995 to regular files, but that's OK. */
997 /* ftruncate is needed because opt.dfp is opened in append
998 mode if opt.always_rest is set. */
999 ftruncate (fileno (fp), 0);
1006 logprintf (LOG_VERBOSE, _("Length: %s"), legible (*len));
1008 logprintf (LOG_VERBOSE, _(" [%s to go]"), legible (*len - restval));
1009 logputs (LOG_VERBOSE, "\n");
1010 expected_bytes = *len; /* for get_contents/show_progress */
1012 else if (expected_bytes)
1014 logprintf (LOG_VERBOSE, _("Length: %s"), legible (expected_bytes));
1016 logprintf (LOG_VERBOSE, _(" [%s to go]"),
1017 legible (expected_bytes - restval));
1018 logputs (LOG_VERBOSE, _(" (unauthoritative)\n"));
1021 /* Get the contents of the document. */
1022 res = get_contents (dtsock, fp, len, restval, expected_bytes, &con->rbuf,
1024 tms = time_str (NULL);
1025 tmrate = retr_rate (*len - restval, con->dltime, 0);
1026 /* Close data connection socket. */
1028 /* Close the local file. */
1030 /* Close or flush the file. We have to be careful to check for
1031 error here. Checking the result of fwrite() is not enough --
1032 errors could go unnoticed! */
1034 if (!opt.dfp || con->cmd & DO_LIST)
1035 flush_res = fclose (fp);
1037 flush_res = fflush (fp);
1038 if (flush_res == EOF)
1042 /* If get_contents couldn't write to fp, bail out. */
1045 logprintf (LOG_NOTQUIET, _("%s: %s, closing control connection.\n"),
1046 con->target, strerror (errno));
1048 rbuf_uninitialize (&con->rbuf);
1053 logprintf (LOG_NOTQUIET, _("%s (%s) - Data connection: %s; "),
1054 tms, tmrate, strerror (errno));
1055 if (opt.server_response)
1056 logputs (LOG_ALWAYS, "\n");
1059 /* Get the server to tell us if everything is retrieved. */
1060 err = ftp_response (&con->rbuf, &respline);
1061 /* ...and empty the buffer. */
1062 rbuf_discard (&con->rbuf);
1066 /* The control connection is decidedly closed. Print the time
1067 only if it hasn't already been printed. */
1069 logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
1070 logputs (LOG_NOTQUIET, _("Control connection closed.\n"));
1071 /* If there is an error on the control connection, close it, but
1072 return FTPRETRINT, since there is a possibility that the
1073 whole file was retrieved nevertheless (but that is for
1074 ftp_loop_internal to decide). */
1076 rbuf_uninitialize (&con->rbuf);
1078 } /* err != FTPOK */
1079 /* If retrieval failed for any reason, return FTPRETRINT, but do not
1080 close socket, since the control connection is still alive. If
1081 there is something wrong with the control connection, it will
1082 become apparent later. */
1083 if (*respline != '2')
1087 logprintf (LOG_NOTQUIET, "%s (%s) - ", tms, tmrate);
1088 logputs (LOG_NOTQUIET, _("Data transfer aborted.\n"));
1095 /* What now? The data connection was erroneous, whereas the
1096 response says everything is OK. We shall play it safe. */
1100 if (!(cmd & LEAVE_PENDING))
1102 /* I should probably send 'QUIT' and check for a reply, but this
1103 is faster. #### Is it OK, though? */
1105 rbuf_uninitialize (&con->rbuf);
1107 /* If it was a listing, and opt.server_response is true,
1109 if (opt.server_response && (con->cmd & DO_LIST))
1111 mkalldirs (con->target);
1112 fp = fopen (con->target, "r");
1114 logprintf (LOG_ALWAYS, "%s: %s\n", con->target, strerror (errno));
1118 /* The lines are being read with read_whole_line because of
1119 no-buffering on opt.lfile. */
1120 while ((line = read_whole_line (fp)))
1122 logprintf (LOG_ALWAYS, "%s\n", line);
1127 } /* con->cmd & DO_LIST && server_response */
1129 return RETRFINISHED;
1132 /* A one-file FTP loop. This is the part where FTP retrieval is
1133 retried, and retried, and retried, and...
1135 This loop either gets commands from con, or (if ON_YOUR_OWN is
1136 set), makes them up to retrieve the file given by the URL. */
1138 ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con)
1143 char *tmrate = NULL;
1148 con->target = url_file_name (u);
1150 if (opt.noclobber && file_exists_p (con->target))
1152 logprintf (LOG_VERBOSE,
1153 _("File `%s' already there, not retrieving.\n"), con->target);
1154 /* If the file is there, we suppose it's retrieved OK. */
1158 /* Remove it if it's a link. */
1159 remove_link (con->target);
1160 if (!opt.output_document)
1163 locf = opt.output_document;
1167 if (con->st & ON_YOUR_OWN)
1168 con->st = ON_YOUR_OWN;
1170 orig_lp = con->cmd & LEAVE_PENDING ? 1 : 0;
1175 /* Increment the pass counter. */
1177 sleep_between_retrievals (count);
1178 if (con->st & ON_YOUR_OWN)
1181 con->cmd |= (DO_RETR | LEAVE_PENDING);
1182 if (rbuf_initialized_p (&con->rbuf))
1183 con->cmd &= ~ (DO_LOGIN | DO_CWD);
1185 con->cmd |= (DO_LOGIN | DO_CWD);
1187 else /* not on your own */
1189 if (rbuf_initialized_p (&con->rbuf))
1190 con->cmd &= ~DO_LOGIN;
1192 con->cmd |= DO_LOGIN;
1193 if (con->st & DONE_CWD)
1194 con->cmd &= ~DO_CWD;
1199 /* Assume no restarting. */
1201 if ((count > 1 || opt.always_rest)
1202 && !(con->cmd & DO_LIST)
1203 && file_exists_p (locf))
1204 if (stat (locf, &st) == 0 && S_ISREG (st.st_mode))
1205 restval = st.st_size;
1207 /* In `-c' is used, check whether the file we're writing to
1208 exists and is of non-zero length. If so, we'll refuse to
1209 truncate it if the server doesn't support continued
1211 if (opt.always_rest && restval > 0)
1212 con->cmd |= NO_TRUNCATE;
1214 /* Get the current time string. */
1215 tms = time_str (NULL);
1216 /* Print fetch message, if opt.verbose. */
1219 char *hurl = url_string (u, 1);
1223 sprintf (tmp, _("(try:%2d)"), count);
1224 logprintf (LOG_VERBOSE, "--%s-- %s\n %s => `%s'\n",
1225 tms, hurl, tmp, locf);
1227 ws_changetitle (hurl, 1);
1231 /* Send getftp the proper length, if fileinfo was provided. */
1236 err = getftp (u, &len, restval, con);
1238 if (!rbuf_initialized_p (&con->rbuf))
1239 con->st &= ~DONE_CWD;
1241 con->st |= DONE_CWD;
1245 case HOSTERR: case CONIMPOSSIBLE: case FWRITEERR: case FOPENERR:
1246 case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case CONTNOTSUPPORTED:
1247 /* Fatal errors, give up. */
1250 case CONSOCKERR: case CONERROR: case FTPSRVERR: case FTPRERR:
1251 case WRITEFAILED: case FTPUNKNOWNTYPE: case CONPORTERR:
1252 case BINDERR: case LISTENERR: case ACCEPTERR:
1253 case FTPPORTERR: case FTPLOGREFUSED: case FTPINVPASV:
1254 printwhat (count, opt.ntry);
1255 /* non-fatal errors */
1259 /* If the control connection was closed, the retrieval
1260 will be considered OK if f->size == len. */
1261 if (!f || len != f->size)
1263 printwhat (count, opt.ntry);
1275 tms = time_str (NULL);
1277 tmrate = retr_rate (len - restval, con->dltime, 0);
1279 /* If we get out of the switch above without continue'ing, we've
1280 successfully downloaded a file. Remember this fact. */
1281 downloaded_file (FILE_DOWNLOADED_NORMALLY, locf);
1283 if (con->st & ON_YOUR_OWN)
1285 CLOSE (RBUF_FD (&con->rbuf));
1286 rbuf_uninitialize (&con->rbuf);
1289 logprintf (LOG_VERBOSE, _("%s (%s) - `%s' saved [%ld]\n\n"),
1290 tms, tmrate, locf, len);
1291 if (!opt.verbose && !opt.quiet)
1293 /* Need to hide the password from the URL. The `if' is here
1294 so that we don't do the needless allocation every
1296 char *hurl = url_string (u, 1);
1297 logprintf (LOG_NONVERBOSE, "%s URL: %s [%ld] -> \"%s\" [%d]\n",
1298 tms, hurl, len, locf, count);
1302 if ((con->cmd & DO_LIST))
1303 /* This is a directory listing file. */
1305 if (!opt.remove_listing)
1306 /* --dont-remove-listing was specified, so do count this towards the
1307 number of bytes and files downloaded. */
1309 total_downloaded_bytes += len;
1313 /* Deletion of listing files is not controlled by --delete-after, but
1314 by the more specific option --dont-remove-listing, and the code
1315 to do this deletion is in another function. */
1317 else if (!opt.spider)
1318 /* This is not a directory listing file. */
1320 /* Unlike directory listing files, don't pretend normal files weren't
1321 downloaded if they're going to be deleted. People seeding proxies,
1322 for instance, may want to know how many bytes and files they've
1323 downloaded through it. */
1324 total_downloaded_bytes += len;
1327 if (opt.delete_after)
1329 DEBUGP (("Removing file due to --delete-after in"
1330 " ftp_loop_internal():\n"));
1331 logprintf (LOG_VERBOSE, _("Removing %s.\n"), locf);
1333 logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1337 /* Restore the original leave-pendingness. */
1339 con->cmd |= LEAVE_PENDING;
1341 con->cmd &= ~LEAVE_PENDING;
1343 } while (!opt.ntry || (count < opt.ntry));
1345 if (rbuf_initialized_p (&con->rbuf) && (con->st & ON_YOUR_OWN))
1347 CLOSE (RBUF_FD (&con->rbuf));
1348 rbuf_uninitialize (&con->rbuf);
1353 /* Return the directory listing in a reusable format. The directory
1354 is specifed in u->dir. */
1356 ftp_get_listing (struct url *u, ccon *con, struct fileinfo **f)
1359 char *uf; /* url file name */
1360 char *lf; /* list file name */
1361 char *old_target = con->target;
1363 con->st &= ~ON_YOUR_OWN;
1364 con->cmd |= (DO_LIST | LEAVE_PENDING);
1365 con->cmd &= ~DO_RETR;
1367 /* Find the listing file name. We do it by taking the file name of
1368 the URL and replacing the last component with the listing file
1370 uf = url_file_name (u);
1371 lf = file_merge (uf, LIST_FILENAME);
1373 DEBUGP ((_("Using `%s' as listing tmp file.\n"), lf));
1376 err = ftp_loop_internal (u, NULL, con);
1377 con->target = old_target;
1380 *f = ftp_parse_ls (lf, con->rs);
1383 if (opt.remove_listing)
1386 logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1388 logprintf (LOG_VERBOSE, _("Removed `%s'.\n"), lf);
1391 con->cmd &= ~DO_LIST;
1395 static uerr_t ftp_retrieve_dirs PARAMS ((struct url *, struct fileinfo *,
1397 static uerr_t ftp_retrieve_glob PARAMS ((struct url *, ccon *, int));
1398 static struct fileinfo *delelement PARAMS ((struct fileinfo *,
1399 struct fileinfo **));
1400 static void freefileinfo PARAMS ((struct fileinfo *f));
1402 /* Retrieve a list of files given in struct fileinfo linked list. If
1403 a file is a symbolic link, do not retrieve it, but rather try to
1404 set up a similar link on the local disk, if the symlinks are
1407 If opt.recursive is set, after all files have been retrieved,
1408 ftp_retrieve_dirs will be called to retrieve the directories. */
1410 ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con)
1412 static int depth = 0;
1414 struct fileinfo *orig;
1419 /* Increase the depth. */
1421 if (opt.reclevel != INFINITE_RECURSION && depth > opt.reclevel)
1423 DEBUGP ((_("Recursion depth %d exceeded max. depth %d.\n"),
1424 depth, opt.reclevel));
1432 con->st &= ~ON_YOUR_OWN;
1433 if (!(con->st & DONE_CWD))
1436 con->cmd &= ~DO_CWD;
1437 con->cmd |= (DO_RETR | LEAVE_PENDING);
1439 if (!rbuf_initialized_p (&con->rbuf))
1440 con->cmd |= DO_LOGIN;
1442 con->cmd &= ~DO_LOGIN;
1444 err = RETROK; /* in case it's not used */
1448 char *old_target, *ofile;
1450 if (opt.quota && total_downloaded_bytes > opt.quota)
1455 old_target = con->target;
1457 ofile = xstrdup (u->file);
1458 url_set_file (u, f->name);
1460 con->target = url_file_name (u);
1464 if (opt.timestamping && f->type == FT_PLAINFILE)
1467 /* If conversion of HTML files retrieved via FTP is ever implemented,
1468 we'll need to stat() <file>.orig here when -K has been specified.
1469 I'm not implementing it now since files on an FTP server are much
1470 more likely than files on an HTTP server to legitimately have a
1472 if (!stat (con->target, &st))
1476 /* Else, get it from the file. */
1477 local_size = st.st_size;
1480 /* Modification time granularity is 2 seconds for Windows, so
1481 increase local time by 1 second for later comparison. */
1484 /* Compare file sizes only for servers that tell us correct
1485 values. Assumme sizes being equal for servers that lie
1487 cor_val = (con->rs == ST_UNIX || con->rs == ST_WINNT);
1488 eq_size = cor_val ? (local_size == f->size) : 1 ;
1489 if (f->tstamp <= tml && eq_size)
1491 /* Remote file is older, file sizes can be compared and
1493 logprintf (LOG_VERBOSE, _("\
1494 Remote file no newer than local file `%s' -- not retrieving.\n"), con->target);
1499 /* Remote file is newer or sizes cannot be matched */
1500 logprintf (LOG_VERBOSE, _("\
1501 Remote file is newer than local file `%s' -- retrieving.\n\n"),
1506 /* Sizes do not match */
1507 logprintf (LOG_VERBOSE, _("\
1508 The sizes do not match (local %ld) -- retrieving.\n\n"), local_size);
1511 } /* opt.timestamping && f->type == FT_PLAINFILE */
1515 /* If opt.retr_symlinks is defined, we treat symlinks as
1516 if they were normal files. There is currently no way
1517 to distinguish whether they might be directories, and
1519 if (!opt.retr_symlinks)
1523 logputs (LOG_NOTQUIET,
1524 _("Invalid name of the symlink, skipping.\n"));
1528 /* Check whether we already have the correct
1530 int rc = lstat (con->target, &st);
1533 size_t len = strlen (f->linkto) + 1;
1534 if (S_ISLNK (st.st_mode))
1536 char *link_target = (char *)alloca (len);
1537 size_t n = readlink (con->target, link_target, len);
1539 && (memcmp (link_target, f->linkto, n) == 0))
1541 logprintf (LOG_VERBOSE, _("\
1542 Already have correct symlink %s -> %s\n\n"),
1543 con->target, f->linkto);
1549 logprintf (LOG_VERBOSE, _("Creating symlink %s -> %s\n"),
1550 con->target, f->linkto);
1551 /* Unlink before creating symlink! */
1552 unlink (con->target);
1553 if (symlink (f->linkto, con->target) == -1)
1554 logprintf (LOG_NOTQUIET, "symlink: %s\n",
1556 logputs (LOG_VERBOSE, "\n");
1557 } /* have f->linkto */
1558 #else /* not HAVE_SYMLINK */
1559 logprintf (LOG_NOTQUIET,
1560 _("Symlinks not supported, skipping symlink `%s'.\n"),
1562 #endif /* not HAVE_SYMLINK */
1564 else /* opt.retr_symlinks */
1567 err = ftp_loop_internal (u, f, con);
1568 } /* opt.retr_symlinks */
1572 logprintf (LOG_NOTQUIET, _("Skipping directory `%s'.\n"),
1576 /* Call the retrieve loop. */
1578 err = ftp_loop_internal (u, f, con);
1581 logprintf (LOG_NOTQUIET, _("%s: unknown/unsupported file type.\n"),
1586 /* Set the time-stamp information to the local file. Symlinks
1587 are not to be stamped because it sets the stamp on the
1589 if (!(f->type == FT_SYMLINK && !opt.retr_symlinks)
1592 && file_exists_p (con->target))
1594 /* #### This code repeats in http.c and ftp.c. Move it to a
1596 const char *fl = NULL;
1597 if (opt.output_document)
1599 if (opt.od_known_regular)
1600 fl = opt.output_document;
1605 touch (fl, f->tstamp);
1607 else if (f->tstamp == -1)
1608 logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"), con->target);
1610 if (f->perms && f->type == FT_PLAINFILE && dlthis)
1611 chmod (con->target, f->perms);
1613 DEBUGP (("Unrecognized permissions for %s.\n", con->target));
1615 xfree (con->target);
1616 con->target = old_target;
1618 url_set_file (u, ofile);
1621 /* Break on fatals. */
1622 if (err == QUOTEXC || err == HOSTERR || err == FWRITEERR)
1624 con->cmd &= ~ (DO_CWD | DO_LOGIN);
1628 /* We do not want to call ftp_retrieve_dirs here */
1629 if (opt.recursive &&
1630 !(opt.reclevel != INFINITE_RECURSION && depth >= opt.reclevel))
1631 err = ftp_retrieve_dirs (u, orig, con);
1632 else if (opt.recursive)
1633 DEBUGP ((_("Will not retrieve dirs since depth is %d (max %d).\n"),
1634 depth, opt.reclevel));
1639 /* Retrieve the directories given in a file list. This function works
1640 by simply going through the linked list and calling
1641 ftp_retrieve_glob on each directory entry. The function knows
1642 about excluded directories. */
1644 ftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con)
1646 char *container = NULL;
1647 int container_size = 0;
1649 for (; f; f = f->next)
1652 char *odir, *newdir;
1654 if (opt.quota && total_downloaded_bytes > opt.quota)
1656 if (f->type != FT_DIRECTORY)
1659 /* Allocate u->dir off stack, but reallocate only if a larger
1660 string is needed. It's a pity there's no "realloca" for an
1661 item on the bottom of the stack. */
1662 size = strlen (u->dir) + 1 + strlen (f->name) + 1;
1663 if (size > container_size)
1664 container = (char *)alloca (size);
1669 || (*odir == '/' && *(odir + 1) == '\0'))
1670 /* If ODIR is empty or just "/", simply append f->name to
1671 ODIR. (In the former case, to preserve u->dir being
1672 relative; in the latter case, to avoid double slash.) */
1673 sprintf (newdir, "%s%s", odir, f->name);
1675 /* Else, use a separator. */
1676 sprintf (newdir, "%s/%s", odir, f->name);
1678 DEBUGP (("Composing new CWD relative to the initial directory.\n"));
1679 DEBUGP ((" odir = '%s'\n f->name = '%s'\n newdir = '%s'\n\n",
1680 odir, f->name, newdir));
1681 if (!accdir (newdir, ALLABS))
1683 logprintf (LOG_VERBOSE, _("\
1684 Not descending to `%s' as it is excluded/not-included.\n"), newdir);
1688 con->st &= ~DONE_CWD;
1690 odir = xstrdup (u->dir); /* because url_set_dir will free
1692 url_set_dir (u, newdir);
1693 ftp_retrieve_glob (u, con, GETALL);
1694 url_set_dir (u, odir);
1697 /* Set the time-stamp? */
1700 if (opt.quota && total_downloaded_bytes > opt.quota)
1706 /* Return non-zero if S has a leading '/' or contains '../' */
1708 has_insecure_name_p (const char *s)
1713 if (strstr(s, "../") != 0)
1719 /* A near-top-level function to retrieve the files in a directory.
1720 The function calls ftp_get_listing, to get a linked list of files.
1721 Then it weeds out the file names that do not match the pattern.
1722 ftp_retrieve_list is called with this updated list as an argument.
1724 If the argument ACTION is GETONE, just download the file (but first
1725 get the listing, so that the time-stamp is heeded); if it's GLOBALL,
1726 use globbing; if it's GETALL, download the whole directory. */
1728 ftp_retrieve_glob (struct url *u, ccon *con, int action)
1730 struct fileinfo *f, *start;
1733 con->cmd |= LEAVE_PENDING;
1735 res = ftp_get_listing (u, con, &start);
1738 /* First: weed out that do not conform the global rules given in
1739 opt.accepts and opt.rejects. */
1740 if (opt.accepts || opt.rejects)
1745 if (f->type != FT_DIRECTORY && !acceptable (f->name))
1747 logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"), f->name);
1748 f = delelement (f, &start);
1754 /* Remove all files with possible harmful names */
1758 if (has_insecure_name_p (f->name))
1760 logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"), f->name);
1761 f = delelement (f, &start);
1766 /* Now weed out the files that do not match our globbing pattern.
1767 If we are dealing with a globbing pattern, that is. */
1768 if (*u->file && (action == GLOBALL || action == GETONE))
1775 matchres = fnmatch (u->file, f->name, 0);
1778 logprintf (LOG_NOTQUIET, "%s: %s\n", con->target,
1782 if (matchres == FNM_NOMATCH)
1783 f = delelement (f, &start); /* delete the element from the list */
1785 f = f->next; /* leave the element in the list */
1789 freefileinfo (start);
1790 return RETRBADPATTERN;
1796 /* Just get everything. */
1797 ftp_retrieve_list (u, start, con);
1801 if (action == GLOBALL)
1804 /* #### This message SUCKS. We should see what was the
1805 reason that nothing was retrieved. */
1806 logprintf (LOG_VERBOSE, _("No matches on pattern `%s'.\n"), u->file);
1808 else /* GETONE or GETALL */
1810 /* Let's try retrieving it anyway. */
1811 con->st |= ON_YOUR_OWN;
1812 res = ftp_loop_internal (u, NULL, con);
1816 freefileinfo (start);
1817 if (opt.quota && total_downloaded_bytes > opt.quota)
1820 /* #### Should we return `res' here? */
1824 /* The wrapper that calls an appropriate routine according to contents
1825 of URL. Inherently, its capabilities are limited on what can be
1826 encoded into a URL. */
1828 ftp_loop (struct url *u, int *dt, struct url *proxy)
1830 ccon con; /* FTP connection */
1835 memset (&con, 0, sizeof (con));
1837 rbuf_uninitialize (&con.rbuf);
1838 con.st = ON_YOUR_OWN;
1842 res = RETROK; /* in case it's not used */
1844 /* If the file name is empty, the user probably wants a directory
1845 index. We'll provide one, properly HTML-ized. Unless
1846 opt.htmlify is 0, of course. :-) */
1847 if (!*u->file && !opt.recursive)
1850 res = ftp_get_listing (u, &con, &f);
1854 if (opt.htmlify && !opt.spider)
1856 char *filename = (opt.output_document
1857 ? xstrdup (opt.output_document)
1858 : (con.target ? xstrdup (con.target)
1859 : url_file_name (u)));
1860 res = ftp_index (filename, u, f);
1861 if (res == FTPOK && opt.verbose)
1863 if (!opt.output_document)
1867 if (stat (filename, &st) == 0)
1871 logprintf (LOG_NOTQUIET,
1872 _("Wrote HTML-ized index to `%s' [%ld].\n"),
1876 logprintf (LOG_NOTQUIET,
1877 _("Wrote HTML-ized index to `%s'.\n"),
1887 int wild = has_wildcards_p (u->file);
1888 if ((opt.ftp_glob && wild) || opt.recursive || opt.timestamping)
1890 /* ftp_retrieve_glob is a catch-all function that gets called
1891 if we need globbing, time-stamping or recursion. Its
1892 third argument is just what we really need. */
1893 res = ftp_retrieve_glob (u, &con,
1894 (opt.ftp_glob && wild) ? GLOBALL : GETONE);
1897 res = ftp_loop_internal (u, NULL, &con);
1903 /* If a connection was left, quench it. */
1904 if (rbuf_initialized_p (&con.rbuf))
1905 CLOSE (RBUF_FD (&con.rbuf));
1906 FREE_MAYBE (con.id);
1908 FREE_MAYBE (con.target);
1913 /* Delete an element from the fileinfo linked list. Returns the
1914 address of the next element, or NULL if the list is exhausted. It
1915 can modify the start of the list. */
1916 static struct fileinfo *
1917 delelement (struct fileinfo *f, struct fileinfo **start)
1919 struct fileinfo *prev = f->prev;
1920 struct fileinfo *next = f->next;
1923 FREE_MAYBE (f->linkto);
1935 /* Free the fileinfo linked list of files. */
1937 freefileinfo (struct fileinfo *f)
1941 struct fileinfo *next = f->next;