extern char ftp_last_respline[];
+extern FILE *output_stream;
+extern int output_stream_regular;
+
typedef struct
{
int st; /* connection status */
/* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in
- the string S, and return the number converted to long, if found, 0
+ the string S, and return the number converted to wgint, if found, 0
otherwise. */
-static long
+static wgint
ftp_expected_bytes (const char *s)
{
- long res;
+ wgint res;
while (1)
{
++s;
if (!*s)
return 0;
- for (++s; *s && ISSPACE (*s); s++);
- if (!*s)
- return 0;
- if (!ISDIGIT (*s))
- continue;
- res = 0;
- do
- {
- res = (*s - '0') + 10 * res;
- ++s;
- }
- while (*s && ISDIGIT (*s));
+ ++s; /* skip the '(' */
+ res = str_to_wgint (s, (char **) &s, 10);
if (!*s)
return 0;
while (*s && ISSPACE (*s))
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)
+getftp (struct url *u, wgint *len, wgint restval, ccon *con)
{
int csock, dtsock, local_sock, res;
- uerr_t err;
+ uerr_t err = RETROK; /* appease the compiler */
FILE *fp;
char *user, *passwd, *respline;
char *tms, *tmrate;
int cmd = con->cmd;
int pasv_mode_open = 0;
- long expected_bytes = 0L;
+ wgint expected_bytes = 0L;
+ int rest_failed = 0;
+ int flags;
+ wgint rd_size;
assert (con != NULL);
assert (con->target != NULL);
return (retryable_socket_connect_error (errno)
? CONERROR : CONIMPOSSIBLE);
+ if (cmd & LEAVE_PENDING)
+ con->csock = csock;
+ else
+ con->csock = -1;
+
/* Second: Login with proper USER/PASS sequence. */
logprintf (LOG_VERBOSE, _("Logging in as %s ... "), user);
if (opt.server_response)
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
return err;
break;
case FTPSRVERR:
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("Error in server greeting.\n"));
fd_close (csock);
+ con->csock = -1;
return err;
break;
case WRITEFAILED:
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
return err;
break;
case FTPLOGREFUSED:
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("The server refuses login.\n"));
fd_close (csock);
+ con->csock = -1;
return FTPLOGREFUSED;
break;
case FTPLOGINC:
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("Login incorrect.\n"));
fd_close (csock);
+ con->csock = -1;
return FTPLOGINC;
break;
case FTPOK:
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
return err;
break;
case FTPSRVERR:
if (!opt.server_response)
logprintf (LOG_VERBOSE, "==> PWD ... ");
- err = ftp_pwd(csock, &con->id);
+ err = ftp_pwd (csock, &con->id);
/* FTPRERR */
switch (err)
{
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
return err;
break;
case FTPSRVERR :
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
return err;
break;
case WRITEFAILED:
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
return err;
break;
case FTPUNKNOWNTYPE:
_("Unknown type `%c', closing control connection.\n"),
type_char);
fd_close (csock);
+ con->csock = -1;
return err;
case FTPOK:
/* Everything is OK. */
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
return err;
break;
case WRITEFAILED:
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
return err;
break;
case FTPNSFOD:
logprintf (LOG_NOTQUIET, _("No such directory `%s'.\n\n"),
u->dir);
fd_close (csock);
+ con->csock = -1;
return err;
break;
case FTPOK:
logprintf (LOG_VERBOSE, "==> SIZE %s ... ", u->file);
}
- err = ftp_size(csock, u->file, len);
+ err = ftp_size (csock, u->file, len);
/* FTPRERR */
switch (err)
{
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
return err;
break;
case FTPOK:
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
return err;
break;
case WRITEFAILED:
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
return err;
break;
case FTPNOPASV:
default:
abort ();
break;
- } /* switch(err) */
+ } /* switch (err) */
if (err==FTPOK)
{
DEBUGP (("trying to connect to %s port %d\n",
{
int save_errno = errno;
fd_close (csock);
- logprintf (LOG_VERBOSE, _("couldn't connect to %s port %hu: %s\n"),
+ con->csock = -1;
+ logprintf (LOG_VERBOSE, _("couldn't connect to %s port %d: %s\n"),
pretty_print_address (&passive_addr), passive_port,
strerror (save_errno));
return (retryable_socket_connect_error (save_errno)
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
fd_close (dtsock);
fd_close (local_sock);
return err;
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
fd_close (dtsock);
fd_close (local_sock);
return err;
logputs (LOG_VERBOSE, "\n");
logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
fd_close (csock);
+ con->csock = -1;
fd_close (dtsock);
fd_close (local_sock);
return err;
logputs (LOG_VERBOSE, "\n");
logputs (LOG_NOTQUIET, _("Invalid PORT.\n"));
fd_close (csock);
+ con->csock = -1;
fd_close (dtsock);
fd_close (local_sock);
return err;
if (restval && (cmd & DO_RETR))
{
if (!opt.server_response)
- logprintf (LOG_VERBOSE, "==> REST %ld ... ", restval);
+ logprintf (LOG_VERBOSE, "==> REST %s ... ", number_to_static_string (restval));
err = ftp_rest (csock, restval);
/* FTPRERR, WRITEFAILED, FTPRESTFAIL */
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
fd_close (dtsock);
fd_close (local_sock);
return err;
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
fd_close (dtsock);
fd_close (local_sock);
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"),
- con->target);
- fd_close (csock);
- fd_close (dtsock);
- fd_close (local_sock);
- return CONTNOTSUPPORTED;
- }
logputs (LOG_VERBOSE, _("\nREST failed, starting from scratch.\n"));
- restval = 0L;
+ rest_failed = 1;
break;
case FTPOK:
/* fine and dandy */
if (opt.spider)
{
fd_close (csock);
+ con->csock = -1;
fd_close (dtsock);
fd_close (local_sock);
return RETRFINISHED;
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
fd_close (dtsock);
fd_close (local_sock);
return err;
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
fd_close (dtsock);
fd_close (local_sock);
return err;
logputs (LOG_NOTQUIET, _("\
Error in server response, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
fd_close (dtsock);
fd_close (local_sock);
return err;
logputs (LOG_NOTQUIET,
_("Write failed, closing control connection.\n"));
fd_close (csock);
+ con->csock = -1;
fd_close (dtsock);
fd_close (local_sock);
return err;
}
}
- /* Open the file -- if opt.dfp is set, use it instead. */
- if (!opt.dfp || con->cmd & DO_LIST)
+ /* Open the file -- if output_stream is set, use it instead. */
+ if (!output_stream || con->cmd & DO_LIST)
{
mkalldirs (con->target);
if (opt.backups)
rotate_backups (con->target);
- /* #### Is this correct? */
- chmod (con->target, 0600);
- fp = fopen (con->target, restval ? "ab" : "wb");
+ if (restval)
+ fp = fopen (con->target, "ab");
+ else if (opt.noclobber || opt.always_rest || opt.timestamping || opt.dirstruct
+ || opt.output_document)
+ fp = fopen (con->target, "wb");
+ else
+ {
+ fp = fopen_excl (con->target, 0);
+ if (!fp && errno == EEXIST)
+ {
+ /* We cannot just invent a new name and use it (which is
+ what functions like unique_create typically do)
+ because we told the user we'd use this name.
+ Instead, return and retry the download. */
+ logprintf (LOG_NOTQUIET, _("%s has sprung into existence.\n"),
+ con->target);
+ fd_close (csock);
+ con->csock = -1;
+ fd_close (dtsock);
+ fd_close (local_sock);
+ return FOPEN_EXCL_ERR;
+ }
+ }
if (!fp)
{
logprintf (LOG_NOTQUIET, "%s: %s\n", con->target, strerror (errno));
fd_close (csock);
+ con->csock = -1;
fd_close (dtsock);
fd_close (local_sock);
return FOPENERR;
}
}
else
- {
- extern int global_download_count;
- fp = opt.dfp;
-
- /* Rewind the output document if the download starts over and if
- this is the first download. See gethttp() for a longer
- explanation. */
- if (!restval && global_download_count == 0 && opt.dfp != stdout)
- {
- /* This will silently fail for streams that don't correspond
- to regular files, but that's OK. */
- rewind (fp);
- /* ftruncate is needed because opt.dfp is opened in append
- mode if opt.always_rest is set. */
- ftruncate (fileno (fp), 0);
- clearerr (fp);
- }
- }
+ fp = output_stream;
if (*len)
{
}
/* Get the contents of the document. */
- res = fd_read_body (dtsock, fp, len, restval, expected_bytes, 0,
- &con->dltime);
+ flags = 0;
+ if (restval && rest_failed)
+ flags |= rb_skip_startpos;
+ *len = restval;
+ rd_size = 0;
+ res = fd_read_body (dtsock, fp,
+ expected_bytes ? expected_bytes - restval : 0,
+ restval, &rd_size, len, &con->dltime, flags);
+
tms = time_str (NULL);
- tmrate = retr_rate (*len - restval, con->dltime, 0);
+ tmrate = retr_rate (rd_size, con->dltime, 0);
/* Close data connection socket. */
fd_close (dtsock);
fd_close (local_sock);
error here. Checking the result of fwrite() is not enough --
errors could go unnoticed! */
int flush_res;
- if (!opt.dfp || con->cmd & DO_LIST)
+ if (!output_stream || con->cmd & DO_LIST)
flush_res = fclose (fp);
else
flush_res = fflush (fp);
logprintf (LOG_NOTQUIET, _("%s: %s, closing control connection.\n"),
con->target, strerror (errno));
fd_close (csock);
+ con->csock = -1;
return FWRITEERR;
}
else if (res == -1)
whole file was retrieved nevertheless (but that is for
ftp_loop_internal to decide). */
fd_close (csock);
+ con->csock = -1;
return FTPRETRINT;
} /* err != FTPOK */
/* If retrieval failed for any reason, return FTPRETRINT, but do not
if (!(cmd & LEAVE_PENDING))
{
- /* I should probably send 'QUIT' and check for a reply, but this
- is faster. #### Is it OK, though? */
+ /* Closing the socket is faster than sending 'QUIT' and the
+ effect is the same. */
fd_close (csock);
+ con->csock = -1;
}
/* If it was a listing, and opt.server_response is true,
print it out. */
ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con)
{
int count, orig_lp;
- long restval, len;
+ wgint restval, len = 0;
char *tms, *locf;
char *tmrate = NULL;
uerr_t err;
- struct stat st;
+ struct_stat st;
if (!con->target)
con->target = url_file_name (u);
con->cmd |= DO_CWD;
}
- /* Assume no restarting. */
- restval = 0L;
- if ((count > 1 || opt.always_rest)
- && !(con->cmd & DO_LIST)
- && file_exists_p (locf))
- if (stat (locf, &st) == 0 && S_ISREG (st.st_mode))
- restval = st.st_size;
-
- /* In `-c' is used, check whether the file we're writing to
- exists and is of non-zero length. If so, we'll refuse to
- truncate it if the server doesn't support continued
- downloads. */
- if (opt.always_rest && restval > 0)
- con->cmd |= NO_TRUNCATE;
+ /* Decide whether or not to restart. */
+ restval = 0;
+ if (count > 1)
+ restval = len; /* start where the previous run left off */
+ else if (opt.always_rest
+ && stat (locf, &st) == 0
+ && S_ISREG (st.st_mode))
+ restval = st.st_size;
/* Get the current time string. */
tms = time_str (NULL);
if (opt.verbose)
{
char *hurl = url_string (u, 1);
- char tmp[15];
+ char tmp[256];
strcpy (tmp, " ");
if (count > 1)
sprintf (tmp, _("(try:%2d)"), count);
logprintf (LOG_VERBOSE, "--%s-- %s\n %s => `%s'\n",
tms, hurl, tmp, locf);
#ifdef WINDOWS
- ws_changetitle (hurl, 1);
+ ws_changetitle (hurl);
#endif
xfree (hurl);
}
case CONSOCKERR: case CONERROR: case FTPSRVERR: case FTPRERR:
case WRITEFAILED: case FTPUNKNOWNTYPE: case FTPSYSERR:
case FTPPORTERR: case FTPLOGREFUSED: case FTPINVPASV:
+ case FOPEN_EXCL_ERR:
printwhat (count, opt.ntry);
/* non-fatal errors */
+ if (err == FOPEN_EXCL_ERR)
+ {
+ /* Re-determine the file name. */
+ xfree_null (con->target);
+ con->target = url_file_name (u);
+ locf = con->target;
+ }
continue;
break;
case FTPRETRINT:
/* Not as great. */
abort ();
}
- /* Time? */
tms = time_str (NULL);
if (!opt.spider)
tmrate = retr_rate (len - restval, con->dltime, 0);
con->csock = -1;
}
if (!opt.spider)
- logprintf (LOG_VERBOSE, _("%s (%s) - `%s' saved [%ld]\n\n"),
- tms, tmrate, locf, len);
+ logprintf (LOG_VERBOSE, _("%s (%s) - `%s' saved [%s]\n\n"),
+ tms, tmrate, locf, number_to_static_string (len));
if (!opt.verbose && !opt.quiet)
{
/* Need to hide the password from the URL. The `if' is here
so that we don't do the needless allocation every
time. */
char *hurl = url_string (u, 1);
- logprintf (LOG_NONVERBOSE, "%s URL: %s [%ld] -> \"%s\" [%d]\n",
- tms, hurl, len, locf, count);
+ logprintf (LOG_NONVERBOSE, "%s URL: %s [%s] -> \"%s\" [%d]\n",
+ tms, hurl, number_to_static_string (len), locf, count);
xfree (hurl);
}
static int depth = 0;
uerr_t err;
struct fileinfo *orig;
- long local_size;
+ wgint local_size;
time_t tml;
int dlthis;
dlthis = 1;
if (opt.timestamping && f->type == FT_PLAINFILE)
{
- struct stat st;
+ struct_stat st;
/* If conversion of HTML files retrieved via FTP is ever implemented,
we'll need to stat() <file>.orig here when -K has been specified.
I'm not implementing it now since files on an FTP server are much
{
/* Sizes do not match */
logprintf (LOG_VERBOSE, _("\
-The sizes do not match (local %ld) -- retrieving.\n\n"), local_size);
+The sizes do not match (local %s) -- retrieving.\n\n"),
+ number_to_static_string (local_size));
}
}
} /* opt.timestamping && f->type == FT_PLAINFILE */
_("Invalid name of the symlink, skipping.\n"));
else
{
- struct stat st;
+ struct_stat st;
/* Check whether we already have the correct
symbolic link. */
int rc = lstat (con->target, &st);
const char *fl = NULL;
if (opt.output_document)
{
- if (opt.od_known_regular)
+ if (output_stream_regular)
fl = opt.output_document;
}
else
if (*s == '/')
return 1;
- if (strstr(s, "../") != 0)
+ if (strstr (s, "../") != 0)
return 1;
return 0;
{
if (!opt.output_document)
{
- struct stat st;
- long sz;
+ struct_stat st;
+ wgint sz;
if (stat (filename, &st) == 0)
sz = st.st_size;
else
sz = -1;
logprintf (LOG_NOTQUIET,
- _("Wrote HTML-ized index to `%s' [%ld].\n"),
- filename, sz);
+ _("Wrote HTML-ized index to `%s' [%s].\n"),
+ filename, number_to_static_string (sz));
}
else
logprintf (LOG_NOTQUIET,