Published in <sxsofuhi4kc.fsf@florida.arsdigita.de>.
+2001-04-01 Hrvoje Niksic <hniksic@arsdigita.com>
+
+ * ftp.c (getftp): Don't start the download from scratch if `-c'
+ was specified, but the file is already fully downloaded.
+
+ * http.c (gethttp): Don't truncate a pre-existing file if `-c' was
+ specified and the server doesn't support continued download.
+ (gethttp): Don't start the download from scratch if `-c' was
+ specified, but the file is already fully downloaded.
+
2001-03-31 Hrvoje Niksic <hniksic@arsdigita.com>
(recursive_retrieve): Don't clear the hash tables at this point at
err = ftp_pwd(&con->rbuf, &con->id);
/* FTPRERR */
switch (err)
- {
- case FTPRERR || FTPSRVERR :
+ {
+ case FTPRERR:
+ case FTPSRVERR :
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
default:
abort ();
break;
- }
+ }
if (!opt.server_response)
logputs (LOG_VERBOSE, _("done.\n"));
return err;
break;
case FTPRESTFAIL:
+ /* If `-c' is specified and the file already existed when
+ Wget was started, it would be a bad idea for us to start
+ downloading it from scratch, effectively truncating it. */
+ if (opt.always_rest && (cmd & NO_TRUNCATE))
+ {
+ logprintf (LOG_NOTQUIET,
+ _("\nREST failed; will not truncate `%s'.\n"),
+ u->local);
+ CLOSE (csock);
+ closeport (dtsock);
+ rbuf_uninitialize (&con->rbuf);
+ return CONTNOTSUPPORTED;
+ }
logputs (LOG_VERBOSE, _("\nREST failed, starting from scratch.\n"));
restval = 0L;
break;
static uerr_t
ftp_loop_internal (struct urlinfo *u, struct fileinfo *f, ccon *con)
{
- int count, orig_lp;
+ int count, orig_lp, no_truncate;
long restval, len;
char *tms, *tmrate, *locf;
uerr_t err;
orig_lp = con->cmd & LEAVE_PENDING ? 1 : 0;
+ /* In `-c' is used, check whether the file we're writing to exists
+ before we've done anything. If so, we'll refuse to truncate it
+ if the server doesn't support continued downloads. */
+ no_truncate = 0;
+ if (opt.always_rest)
+ no_truncate = file_exists_p (locf);
+
/* THE loop. */
do
{
else
con->cmd |= DO_CWD;
}
+ if (no_truncate)
+ con->cmd |= NO_TRUNCATE;
/* Assume no restarting. */
restval = 0L;
if ((count > 1 || opt.always_rest)
switch (err)
{
case HOSTERR: case CONREFUSED: case FWRITEERR: case FOPENERR:
- case FTPNSFOD: case FTPLOGINC: case FTPNOPASV:
+ case FTPNSFOD: case FTPLOGINC: case FTPNOPASV: case CONTNOTSUPPORTED:
/* Fatal errors, give up. */
return err;
break;
DO_CWD = 0x0002, /* Change current directory. */
DO_RETR = 0x0004, /* Retrieve the file. */
DO_LIST = 0x0008, /* Retrieve the directory list. */
- LEAVE_PENDING = 0x0010 /* Do not close the socket. */
+ LEAVE_PENDING = 0x0010, /* Do not close the socket. */
+ NO_TRUNCATE = 0x0020 /* Don't truncate the file if REST
+ malfunctions. */
};
enum wget_ftp_fstatus
char *error; /* textual HTTP error */
int statcode; /* status code */
long dltime; /* time of the download */
+ int no_truncate; /* whether truncating the file is
+ forbidden. */
};
/* Free the elements of hstat X. */
}
if (contrange == -1)
- hs->restval = 0;
+ {
+ /* We did not get a content-range header. This means that the
+ server did not honor our `Range' request. Normally, this
+ means we should reset hs->restval and continue normally. */
+
+ /* However, if `-c' is used, we need to be a bit more careful:
+
+ 1. If `-c' is specified and the file already existed when
+ Wget was started, it would be a bad idea for us to start
+ downloading it from scratch, effectively truncating it. I
+ believe this cannot happen unless `-c' was specified.
+
+ 2. If `-c' is used on a file that is already fully
+ downloaded, we're requesting bytes after the end of file,
+ which can result in server not honoring `Range'. If this is
+ the case, `Content-Length' will be equal to the length of the
+ file. */
+ if (opt.always_rest)
+ {
+ /* Check for condition #2. */
+ if (hs->restval == contlen)
+ {
+ logputs (LOG_VERBOSE, _("\
+\n The file is already fully retrieved; nothing to do.\n\n"));
+ /* In case the caller inspects. */
+ hs->len = contlen;
+ hs->res = 0;
+ FREE_MAYBE (type);
+ FREE_MAYBE (hs->newloc);
+ FREE_MAYBE (all_headers);
+ CLOSE_INVALIDATE (sock); /* would be CLOSE_FINISH, but there
+ might be more bytes in the body. */
+ return RETRFINISHED;
+ }
+
+ /* Check for condition #1. */
+ if (hs->no_truncate)
+ {
+ logprintf (LOG_NOTQUIET,
+ _("\
+
+ The server does not support continued download;
+ refusing to truncate `%s'.\n\n"), u->local);
+ return CONTNOTSUPPORTED;
+ }
+
+ /* Fallthrough */
+ }
+
+ hs->restval = 0;
+ }
+
else if (contrange != hs->restval ||
(H_PARTIAL (statcode) && contrange == -1))
{
/* Return if we have no intention of further downloading. */
if (!(*dt & RETROKF) || (*dt & HEAD_ONLY))
{
- /* In case someone cares to look... */
+ /* In case the caller cares to look... */
hs->len = 0L;
hs->res = 0;
FREE_MAYBE (type);
{
/* Would a single s[n]printf() call be faster? --dan
- It wouldn't. sprintf() is horribly slow. At one point I
- profiled Wget, and found that a measurable and
+ Definitely not. sprintf() is horribly slow. It's a
+ different question whether the difference between the two
+ affects a program. Usually I'd say "no", but at one
+ point I profiled Wget, and found that a measurable and
non-negligible amount of time was lost calling sprintf()
in url.c. Replacing sprintf with inline calls to
strcpy() and long_to_string() made a difference.
else
locf = opt.output_document;
+ /* In `-c' is used, check whether the file we're writing to
+ exists before we've done anything. If so, we'll refuse to
+ truncate it if the server doesn't support continued
+ downloads. */
+ if (opt.always_rest)
+ hstat.no_truncate = file_exists_p (locf);
+
/* Time? */
tms = time_str (NULL);
/* Get the new location (with or without the redirection). */
continue;
break;
case HOSTERR: case CONREFUSED: case PROXERR: case AUTHFAILED:
- case SSLERRCTXCREATE:
+ case SSLERRCTXCREATE: case CONTNOTSUPPORTED:
/* Fatal errors just return from the function. */
FREEHSTAT (hstat);
xfree (filename_plus_orig_suffix); /* must precede every return! */
FREEHSTAT (hstat);
return err;
break;
- case CONSSLERR:
+ case CONSSLERR:
/* Another fatal error. */
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, _("Unable to establish SSL connection.\n"));
URLBADHOST, FOPENERR, FWRITEERR, HOK, HLEXC, HEOF,
HERR, RETROK, RECLEVELEXC, FTPACCDENIED, WRONGCODE,
FTPINVPASV, FTPNOPASV,
- RETRFINISHED, READERR, TRYLIMEXC, URLBADPATTERN,
- FILEBADFILE, RANGEERR, RETRBADPATTERN, RETNOTSUP,
- ROBOTSOK, NOROBOTS, PROXERR, AUTHFAILED, QUOTEXC, WRITEFAILED,
+ CONTNOTSUPPORTED, RETRFINISHED, READERR, TRYLIMEXC,
+ URLBADPATTERN, FILEBADFILE, RANGEERR, RETRBADPATTERN,
+ RETNOTSUP, ROBOTSOK, NOROBOTS, PROXERR, AUTHFAILED,
+ QUOTEXC, WRITEFAILED,
SSLERRCERTFILE,SSLERRCERTKEY,SSLERRCTXCREATE
} uerr_t;