X-Git-Url: http://sjero.net/git/?p=wget;a=blobdiff_plain;f=src%2Fftp.c;h=fdac6d49846d6d308f04eb6e109fca311db45786;hp=d99ddb71db43a589ef6dc93d04bb7d090c666478;hb=d9fea91a0a319e348adb504bd3edff148ff3d8a0;hpb=d0f4a1e109f6ac382541d0190db90c7fcbf9d8c3 diff --git a/src/ftp.c b/src/ftp.c index d99ddb71..fdac6d49 100644 --- a/src/ftp.c +++ b/src/ftp.c @@ -47,19 +47,20 @@ so, delete this exception statement from your version. */ #include "wget.h" #include "utils.h" #include "url.h" -#include "rbuf.h" #include "retr.h" #include "ftp.h" #include "connect.h" #include "host.h" -#include "fnmatch.h" #include "netrc.h" #include "convert.h" /* for downloaded_file */ +#include "recur.h" /* for INFINITE_RECURSION */ #ifndef errno extern int errno; #endif +extern LARGE_INT total_downloaded_bytes; + /* File where the "ls -al" listing will be saved. */ #define LIST_FILENAME ".listing" @@ -69,7 +70,7 @@ typedef struct { int st; /* connection status */ int cmd; /* command code */ - struct rbuf rbuf; /* control connection buffer */ + int csock; /* control connection socket */ double dltime; /* time of the download in msecs */ enum stype rs; /* remote system reported by ftp server */ char *id; /* initial directory */ @@ -120,13 +121,119 @@ ftp_expected_bytes (const char *s) return res; } +#ifdef ENABLE_IPV6 +/* + * This function sets up a passive data connection with the FTP server. + * It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv. + */ +static uerr_t +ftp_do_pasv (int csock, ip_address *addr, int *port) +{ + uerr_t err; + + /* We need to determine the address family and need to call + getpeername, so while we're at it, store the address to ADDR. + ftp_pasv and ftp_lpsv can simply override it. */ + if (!socket_ip_address (csock, addr, ENDPOINT_PEER)) + abort (); + + /* If our control connection is over IPv6, then we first try EPSV and then + * LPSV if the former is not supported. If the control connection is over + * IPv4, we simply issue the good old PASV request. */ + switch (addr->type) + { + case IPV4_ADDRESS: + if (!opt.server_response) + logputs (LOG_VERBOSE, "==> PASV ... "); + err = ftp_pasv (csock, addr, port); + break; + case IPV6_ADDRESS: + if (!opt.server_response) + logputs (LOG_VERBOSE, "==> EPSV ... "); + err = ftp_epsv (csock, addr, port); + + /* If EPSV is not supported try LPSV */ + if (err == FTPNOPASV) + { + if (!opt.server_response) + logputs (LOG_VERBOSE, "==> LPSV ... "); + err = ftp_lpsv (csock, addr, port); + } + break; + default: + abort (); + } + + return err; +} + +/* + * This function sets up an active data connection with the FTP server. + * It is merely a wrapper around ftp_eprt, ftp_lprt and ftp_port. + */ +static uerr_t +ftp_do_port (int csock, int *local_sock) +{ + uerr_t err; + ip_address cip; + + if (!socket_ip_address (csock, &cip, ENDPOINT_PEER)) + abort (); + + /* If our control connection is over IPv6, then we first try EPRT and then + * LPRT if the former is not supported. If the control connection is over + * IPv4, we simply issue the good old PORT request. */ + switch (cip.type) + { + case IPV4_ADDRESS: + if (!opt.server_response) + logputs (LOG_VERBOSE, "==> PORT ... "); + err = ftp_port (csock, local_sock); + break; + case IPV6_ADDRESS: + if (!opt.server_response) + logputs (LOG_VERBOSE, "==> EPRT ... "); + err = ftp_eprt (csock, local_sock); + + /* If EPRT is not supported try LPRT */ + if (err == FTPPORTERR) + { + if (!opt.server_response) + logputs (LOG_VERBOSE, "==> LPRT ... "); + err = ftp_lprt (csock, local_sock); + } + break; + default: + abort (); + } + return err; +} +#else + +static uerr_t +ftp_do_pasv (int csock, ip_address *addr, int *port) +{ + if (!opt.server_response) + logputs (LOG_VERBOSE, "==> PASV ... "); + return ftp_pasv (csock, addr, port); +} + +static uerr_t +ftp_do_port (int csock, int *local_sock) +{ + if (!opt.server_response) + logputs (LOG_VERBOSE, "==> PORT ... "); + return ftp_port (csock, local_sock); +} +#endif + /* Retrieves a file with denoted parameters through opening an FTP connection to the server. It always closes the data connection, and closes the control connection in case of error. */ static uerr_t getftp (struct url *u, long *len, long restval, ccon *con) { - int csock, dtsock, res; + int csock, dtsock, local_sock, res; uerr_t err; FILE *fp; char *user, *passwd, *respline; @@ -153,15 +260,14 @@ getftp (struct url *u, long *len, long restval, ccon *con) assert (user && passwd); dtsock = -1; + local_sock = -1; con->dltime = 0; if (!(cmd & DO_LOGIN)) - csock = RBUF_FD (&con->rbuf); + csock = con->csock; else /* cmd & DO_LOGIN */ { char type_char; - struct address_list *al; - char *host = con->proxy ? con->proxy->host : u->host; int port = con->proxy ? con->proxy->port : u->port; char *logname = user; @@ -177,31 +283,18 @@ getftp (struct url *u, long *len, long restval, ccon *con) /* First: Establish the control connection. */ - al = lookup_host (host, 0); - if (!al) + csock = connect_to_host (host, port); + if (csock == E_HOST) return HOSTERR; - set_connection_host_name (host); - csock = connect_to_many (al, port, 0); - set_connection_host_name (NULL); - address_list_release (al); - - if (csock < 0) - return CONNECT_ERROR (errno); - - if (cmd & LEAVE_PENDING) - rbuf_initialize (&con->rbuf, csock); - else - rbuf_uninitialize (&con->rbuf); - - /* Since this is a new connection, we may safely discard - anything left in the buffer. */ - rbuf_discard (&con->rbuf); + else if (csock < 0) + return (retryable_socket_connect_error (errno) + ? CONERROR : CONIMPOSSIBLE); /* Second: Login with proper USER/PASS sequence. */ logprintf (LOG_VERBOSE, _("Logging in as %s ... "), user); if (opt.server_response) logputs (LOG_ALWAYS, "\n"); - err = ftp_login (&con->rbuf, logname, passwd); + err = ftp_login (csock, logname, passwd); if (con->proxy) xfree (logname); @@ -213,37 +306,32 @@ getftp (struct url *u, long *len, long restval, ccon *con) logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; break; case FTPSRVERR: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("Error in server greeting.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; break; case WRITEFAILED: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("Write failed, closing control connection.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; break; case FTPLOGREFUSED: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("The server refuses login.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return FTPLOGREFUSED; break; case FTPLOGINC: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("Login incorrect.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return FTPLOGINC; break; case FTPOK: @@ -258,7 +346,7 @@ Error in server response, closing control connection.\n")); /* Third: Get the system type */ if (!opt.server_response) logprintf (LOG_VERBOSE, "==> SYST ... "); - err = ftp_syst (&con->rbuf, &con->rs); + err = ftp_syst (csock, &con->rs); /* FTPRERR */ switch (err) { @@ -266,8 +354,7 @@ Error in server response, closing control connection.\n")); logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; break; case FTPSRVERR: @@ -289,7 +376,7 @@ Error in server response, closing control connection.\n")); if (!opt.server_response) logprintf (LOG_VERBOSE, "==> PWD ... "); - err = ftp_pwd(&con->rbuf, &con->id); + err = ftp_pwd(csock, &con->id); /* FTPRERR */ switch (err) { @@ -297,13 +384,12 @@ Error in server response, closing control connection.\n")); logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; break; case FTPSRVERR : /* PWD unsupported -- assume "/". */ - FREE_MAYBE (con->id); + xfree_null (con->id); con->id = xstrdup ("/"); break; case FTPOK: @@ -343,7 +429,7 @@ Error in server response, closing control connection.\n")); type_char = ftp_process_type (u->params); if (!opt.server_response) logprintf (LOG_VERBOSE, "==> TYPE %c ... ", type_char); - err = ftp_type (&con->rbuf, type_char); + err = ftp_type (csock, type_char); /* FTPRERR, WRITEFAILED, FTPUNKNOWNTYPE */ switch (err) { @@ -351,16 +437,14 @@ Error in server response, closing control connection.\n")); logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; break; case WRITEFAILED: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("Write failed, closing control connection.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; break; case FTPUNKNOWNTYPE: @@ -368,8 +452,7 @@ Error in server response, closing control connection.\n")); logprintf (LOG_NOTQUIET, _("Unknown type `%c', closing control connection.\n"), type_char); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; case FTPOK: /* Everything is OK. */ @@ -458,7 +541,7 @@ Error in server response, closing control connection.\n")); if (!opt.server_response) logprintf (LOG_VERBOSE, "==> CWD %s ... ", target); - err = ftp_cwd (&con->rbuf, target); + err = ftp_cwd (csock, target); /* FTPRERR, WRITEFAILED, FTPNSFOD */ switch (err) { @@ -466,24 +549,21 @@ Error in server response, closing control connection.\n")); logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; break; case WRITEFAILED: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("Write failed, closing control connection.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; break; case FTPNSFOD: logputs (LOG_VERBOSE, "\n"); logprintf (LOG_NOTQUIET, _("No such directory `%s'.\n\n"), u->dir); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; break; case FTPOK: @@ -508,7 +588,7 @@ Error in server response, closing control connection.\n")); logprintf (LOG_VERBOSE, "==> SIZE %s ... ", u->file); } - err = ftp_size(&con->rbuf, u->file, len); + err = ftp_size(csock, u->file, len); /* FTPRERR */ switch (err) { @@ -517,8 +597,7 @@ Error in server response, closing control connection.\n")); logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; break; case FTPOK: @@ -537,11 +616,9 @@ Error in server response, closing control connection.\n")); { if (opt.ftp_pasv > 0) { - ip_address passive_addr; - unsigned short passive_port; - if (!opt.server_response) - logputs (LOG_VERBOSE, "==> PASV ... "); - err = ftp_pasv (&con->rbuf, &passive_addr, &passive_port); + ip_address passive_addr; + int passive_port; + err = ftp_do_pasv (csock, &passive_addr, &passive_port); /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */ switch (err) { @@ -549,16 +626,14 @@ Error in server response, closing control connection.\n")); logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; break; case WRITEFAILED: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("Write failed, closing control connection.\n")); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return err; break; case FTPNOPASV: @@ -578,16 +653,19 @@ Error in server response, closing control connection.\n")); } /* switch(err) */ if (err==FTPOK) { - dtsock = connect_to_one (&passive_addr, passive_port, 1); + DEBUGP (("trying to connect to %s port %d\n", + pretty_print_address (&passive_addr), + passive_port)); + dtsock = connect_to_ip (&passive_addr, passive_port, NULL); if (dtsock < 0) { int save_errno = errno; - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); - logprintf (LOG_VERBOSE, _("couldn't connect to %s:%hu: %s\n"), + fd_close (csock); + logprintf (LOG_VERBOSE, _("couldn't connect to %s port %hu: %s\n"), pretty_print_address (&passive_addr), passive_port, strerror (save_errno)); - return CONNECT_ERROR (save_errno); + return (retryable_socket_connect_error (save_errno) + ? CONERROR : CONIMPOSSIBLE); } pasv_mode_open = 1; /* Flag to avoid accept port */ @@ -598,53 +676,50 @@ Error in server response, closing control connection.\n")); if (!pasv_mode_open) /* Try to use a port command if PASV failed */ { - if (!opt.server_response) - logputs (LOG_VERBOSE, "==> PORT ... "); - err = ftp_port (&con->rbuf); - /* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR, - LISTENERR), HOSTERR, FTPPORTERR */ + err = ftp_do_port (csock, &local_sock); + /* FTPRERR, WRITEFAILED, bindport (FTPSYSERR), HOSTERR, + FTPPORTERR */ switch (err) { case FTPRERR: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); - CLOSE (csock); - closeport (dtsock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); + fd_close (dtsock); + fd_close (local_sock); return err; break; case WRITEFAILED: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("Write failed, closing control connection.\n")); - CLOSE (csock); - closeport (dtsock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); + fd_close (dtsock); + fd_close (local_sock); return err; break; case CONSOCKERR: logputs (LOG_VERBOSE, "\n"); logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno)); - CLOSE (csock); - closeport (dtsock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); + fd_close (dtsock); + fd_close (local_sock); return err; break; - case CONPORTERR: case BINDERR: case LISTENERR: - /* What now? These problems are local... */ + case FTPSYSERR: logputs (LOG_VERBOSE, "\n"); logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"), strerror (errno)); - closeport (dtsock); + fd_close (dtsock); return err; break; case FTPPORTERR: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("Invalid PORT.\n")); - CLOSE (csock); - closeport (dtsock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); + fd_close (dtsock); + fd_close (local_sock); return err; break; case FTPOK: @@ -664,7 +739,7 @@ Error in server response, closing control connection.\n")); { if (!opt.server_response) logprintf (LOG_VERBOSE, "==> REST %ld ... ", restval); - err = ftp_rest (&con->rbuf, restval); + err = ftp_rest (csock, restval); /* FTPRERR, WRITEFAILED, FTPRESTFAIL */ switch (err) @@ -673,18 +748,18 @@ Error in server response, closing control connection.\n")); logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); - CLOSE (csock); - closeport (dtsock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); + fd_close (dtsock); + fd_close (local_sock); return err; break; case WRITEFAILED: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("Write failed, closing control connection.\n")); - CLOSE (csock); - closeport (dtsock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); + fd_close (dtsock); + fd_close (local_sock); return err; break; case FTPRESTFAIL: @@ -696,9 +771,9 @@ Error in server response, closing control connection.\n")); logprintf (LOG_NOTQUIET, _("\nREST failed; will not truncate `%s'.\n"), con->target); - CLOSE (csock); - closeport (dtsock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); + fd_close (dtsock); + fd_close (local_sock); return CONTNOTSUPPORTED; } logputs (LOG_VERBOSE, _("\nREST failed, starting from scratch.\n")); @@ -723,9 +798,9 @@ Error in server response, closing control connection.\n")); request. */ if (opt.spider) { - CLOSE (csock); - closeport (dtsock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); + fd_close (dtsock); + fd_close (local_sock); return RETRFINISHED; } @@ -738,7 +813,8 @@ Error in server response, closing control connection.\n")); logprintf (LOG_VERBOSE, "==> RETR %s ... ", u->file); } } - err = ftp_retr (&con->rbuf, u->file); + + err = ftp_retr (csock, u->file); /* FTPRERR, WRITEFAILED, FTPNSFOD */ switch (err) { @@ -746,24 +822,25 @@ Error in server response, closing control connection.\n")); logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); - CLOSE (csock); - closeport (dtsock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); + fd_close (dtsock); + fd_close (local_sock); return err; break; case WRITEFAILED: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("Write failed, closing control connection.\n")); - CLOSE (csock); - closeport (dtsock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); + fd_close (dtsock); + fd_close (local_sock); return err; break; case FTPNSFOD: logputs (LOG_VERBOSE, "\n"); logprintf (LOG_NOTQUIET, _("No such file `%s'.\n\n"), u->file); - closeport (dtsock); + fd_close (dtsock); + fd_close (local_sock); return err; break; case FTPOK: @@ -786,7 +863,7 @@ Error in server response, closing control connection.\n")); /* As Maciej W. Rozycki (macro@ds2.pg.gda.pl) says, `LIST' without arguments is better than `LIST .'; confirmed by RFC959. */ - err = ftp_list (&con->rbuf, NULL); + err = ftp_list (csock, NULL); /* FTPRERR, WRITEFAILED */ switch (err) { @@ -794,25 +871,26 @@ Error in server response, closing control connection.\n")); logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("\ Error in server response, closing control connection.\n")); - CLOSE (csock); - closeport (dtsock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); + fd_close (dtsock); + fd_close (local_sock); return err; break; case WRITEFAILED: logputs (LOG_VERBOSE, "\n"); logputs (LOG_NOTQUIET, _("Write failed, closing control connection.\n")); - CLOSE (csock); - closeport (dtsock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); + fd_close (dtsock); + fd_close (local_sock); return err; break; case FTPNSFOD: logputs (LOG_VERBOSE, "\n"); logprintf (LOG_NOTQUIET, _("No such file or directory `%s'.\n\n"), "."); - closeport (dtsock); + fd_close (dtsock); + fd_close (local_sock); return err; break; case FTPOK: @@ -843,10 +921,10 @@ Error in server response, closing control connection.\n")); if (!pasv_mode_open) /* we are not using pasive mode so we need to accept */ { - /* Open the data transmission socket by calling acceptport(). */ - err = acceptport (&dtsock); - /* Possible errors: ACCEPTERR. */ - if (err == ACCEPTERR) + /* Wait for the server to connect to the address we're waiting + at. */ + dtsock = accept_connection (local_sock); + if (dtsock < 0) { logprintf (LOG_NOTQUIET, "accept: %s\n", strerror (errno)); return err; @@ -866,9 +944,9 @@ Error in server response, closing control connection.\n")); if (!fp) { logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, strerror (errno)); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); - closeport (dtsock); + fd_close (csock); + fd_close (dtsock); + fd_close (local_sock); return FOPENERR; } } @@ -910,12 +988,13 @@ Error in server response, closing control connection.\n")); } /* Get the contents of the document. */ - res = get_contents (dtsock, fp, len, restval, expected_bytes, &con->rbuf, - 0, &con->dltime); + res = fd_read_body (dtsock, fp, len, restval, expected_bytes, 0, + &con->dltime); tms = time_str (NULL); tmrate = retr_rate (*len - restval, con->dltime, 0); /* Close data connection socket. */ - closeport (dtsock); + fd_close (dtsock); + fd_close (local_sock); /* Close the local file. */ { /* Close or flush the file. We have to be careful to check for @@ -929,13 +1008,13 @@ Error in server response, closing control connection.\n")); if (flush_res == EOF) res = -2; } + /* If get_contents couldn't write to fp, bail out. */ if (res == -2) { logprintf (LOG_NOTQUIET, _("%s: %s, closing control connection.\n"), con->target, strerror (errno)); - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return FWRITEERR; } else if (res == -1) @@ -947,9 +1026,7 @@ Error in server response, closing control connection.\n")); } /* Get the server to tell us if everything is retrieved. */ - err = ftp_response (&con->rbuf, &respline); - /* ...and empty the buffer. */ - rbuf_discard (&con->rbuf); + err = ftp_response (csock, &respline); if (err != FTPOK) { xfree (respline); @@ -962,8 +1039,7 @@ Error in server response, closing control connection.\n")); return FTPRETRINT, since there is a possibility that the whole file was retrieved nevertheless (but that is for ftp_loop_internal to decide). */ - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); return FTPRETRINT; } /* err != FTPOK */ /* If retrieval failed for any reason, return FTPRETRINT, but do not @@ -991,8 +1067,7 @@ Error in server response, closing control connection.\n")); { /* I should probably send 'QUIT' and check for a reply, but this is faster. #### Is it OK, though? */ - CLOSE (csock); - rbuf_uninitialize (&con->rbuf); + fd_close (csock); } /* If it was a listing, and opt.server_response is true, print it out. */ @@ -1069,14 +1144,14 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con) { con->cmd = 0; con->cmd |= (DO_RETR | LEAVE_PENDING); - if (rbuf_initialized_p (&con->rbuf)) + if (con->csock != -1) con->cmd &= ~ (DO_LOGIN | DO_CWD); else con->cmd |= (DO_LOGIN | DO_CWD); } else /* not on your own */ { - if (rbuf_initialized_p (&con->rbuf)) + if (con->csock != -1) con->cmd &= ~DO_LOGIN; else con->cmd |= DO_LOGIN; @@ -1125,21 +1200,20 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con) len = 0; err = getftp (u, &len, restval, con); - if (!rbuf_initialized_p (&con->rbuf)) + if (con->csock != -1) con->st &= ~DONE_CWD; else con->st |= DONE_CWD; switch (err) { - case HOSTERR: case CONREFUSED: case FWRITEERR: case FOPENERR: + case HOSTERR: case CONIMPOSSIBLE: case FWRITEERR: case FOPENERR: case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case CONTNOTSUPPORTED: /* Fatal errors, give up. */ return err; break; case CONSOCKERR: case CONERROR: case FTPSRVERR: case FTPRERR: - case WRITEFAILED: case FTPUNKNOWNTYPE: case CONPORTERR: - case BINDERR: case LISTENERR: case ACCEPTERR: + case WRITEFAILED: case FTPUNKNOWNTYPE: case FTPSYSERR: case FTPPORTERR: case FTPLOGREFUSED: case FTPINVPASV: printwhat (count, opt.ntry); /* non-fatal errors */ @@ -1172,8 +1246,8 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con) if (con->st & ON_YOUR_OWN) { - CLOSE (RBUF_FD (&con->rbuf)); - rbuf_uninitialize (&con->rbuf); + fd_close (con->csock); + con->csock = -1; } if (!opt.spider) logprintf (LOG_VERBOSE, _("%s (%s) - `%s' saved [%ld]\n\n"), @@ -1196,7 +1270,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con) /* --dont-remove-listing was specified, so do count this towards the number of bytes and files downloaded. */ { - downloaded_increase (len); + total_downloaded_bytes += len; opt.numurls++; } @@ -1211,7 +1285,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con) downloaded if they're going to be deleted. People seeding proxies, for instance, may want to know how many bytes and files they've downloaded through it. */ - downloaded_increase (len); + total_downloaded_bytes += len; opt.numurls++; if (opt.delete_after) @@ -1223,7 +1297,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con) logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno)); } } - + /* Restore the original leave-pendingness. */ if (orig_lp) con->cmd |= LEAVE_PENDING; @@ -1232,10 +1306,10 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con) return RETROK; } while (!opt.ntry || (count < opt.ntry)); - if (rbuf_initialized_p (&con->rbuf) && (con->st & ON_YOUR_OWN)) + if (con->csock != -1 && (con->st & ON_YOUR_OWN)) { - CLOSE (RBUF_FD (&con->rbuf)); - rbuf_uninitialize (&con->rbuf); + fd_close (con->csock); + con->csock = -1; } return TRYLIMEXC; } @@ -1326,7 +1400,7 @@ ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con) con->cmd &= ~DO_CWD; con->cmd |= (DO_RETR | LEAVE_PENDING); - if (!rbuf_initialized_p (&con->rbuf)) + if (con->csock < 0) con->cmd |= DO_LOGIN; else con->cmd &= ~DO_LOGIN; @@ -1337,7 +1411,7 @@ ftp_retrieve_list (struct url *u, struct fileinfo *f, ccon *con) { char *old_target, *ofile; - if (downloaded_exceeds_quota ()) + if (opt.quota && total_downloaded_bytes > opt.quota) { --depth; return QUOTEXC; @@ -1498,7 +1572,10 @@ Already have correct symlink %s -> %s\n\n"), logprintf (LOG_NOTQUIET, _("%s: corrupt time-stamp.\n"), con->target); if (f->perms && f->type == FT_PLAINFILE && dlthis) - chmod (con->target, f->perms); + { + if (opt.preserve_perm) + chmod (con->target, f->perms); + } else DEBUGP (("Unrecognized permissions for %s.\n", con->target)); @@ -1541,7 +1618,7 @@ ftp_retrieve_dirs (struct url *u, struct fileinfo *f, ccon *con) int size; char *odir, *newdir; - if (downloaded_exceeds_quota ()) + if (opt.quota && total_downloaded_bytes > opt.quota) break; if (f->type != FT_DIRECTORY) continue; @@ -1587,12 +1664,24 @@ Not descending to `%s' as it is excluded/not-included.\n"), newdir); /* Set the time-stamp? */ } - if (opt.quota && opt.downloaded > opt.quota) + if (opt.quota && total_downloaded_bytes > opt.quota) return QUOTEXC; else return RETROK; } +/* Return non-zero if S has a leading '/' or contains '../' */ +static int +has_insecure_name_p (const char *s) +{ + if (*s == '/') + return 1; + + if (strstr(s, "../") != 0) + return 1; + + return 0; +} /* A near-top-level function to retrieve the files in a directory. The function calls ftp_get_listing, to get a linked list of files. @@ -1605,20 +1694,19 @@ Not descending to `%s' as it is excluded/not-included.\n"), newdir); static uerr_t ftp_retrieve_glob (struct url *u, ccon *con, int action) { - struct fileinfo *f, *orig, *start; + struct fileinfo *f, *start; uerr_t res; con->cmd |= LEAVE_PENDING; - res = ftp_get_listing (u, con, &orig); + res = ftp_get_listing (u, con, &start); if (res != RETROK) return res; - start = orig; /* First: weed out that do not conform the global rules given in opt.accepts and opt.rejects. */ if (opt.accepts || opt.rejects) { - f = orig; + f = start; while (f) { if (f->type != FT_DIRECTORY && !acceptable (f->name)) @@ -1631,10 +1719,10 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action) } } /* Remove all files with possible harmful names */ - f = orig; + f = start; while (f) { - if (has_insecure_name_p(f->name)) + if (has_insecure_name_p (f->name)) { logprintf (LOG_VERBOSE, _("Rejecting `%s'.\n"), f->name); f = delelement (f, &start); @@ -1693,7 +1781,7 @@ ftp_retrieve_glob (struct url *u, ccon *con, int action) } } freefileinfo (start); - if (downloaded_exceeds_quota ()) + if (opt.quota && total_downloaded_bytes > opt.quota) return QUOTEXC; else /* #### Should we return `res' here? */ @@ -1713,7 +1801,7 @@ ftp_loop (struct url *u, int *dt, struct url *proxy) memset (&con, 0, sizeof (con)); - rbuf_uninitialize (&con.rbuf); + con.csock = -1; con.st = ON_YOUR_OWN; con.rs = ST_UNIX; con.id = NULL; @@ -1780,11 +1868,11 @@ ftp_loop (struct url *u, int *dt, struct url *proxy) if (res == RETROK) *dt |= RETROKF; /* If a connection was left, quench it. */ - if (rbuf_initialized_p (&con.rbuf)) - CLOSE (RBUF_FD (&con.rbuf)); - FREE_MAYBE (con.id); + if (con.csock != -1) + fd_close (con.csock); + xfree_null (con.id); con.id = NULL; - FREE_MAYBE (con.target); + xfree_null (con.target); con.target = NULL; return res; } @@ -1799,7 +1887,7 @@ delelement (struct fileinfo *f, struct fileinfo **start) struct fileinfo *next = f->next; xfree (f->name); - FREE_MAYBE (f->linkto); + xfree_null (f->linkto); xfree (f); if (next)