mirror of
https://github.com/mirror/wget.git
synced 2025-01-01 07:50:11 +08:00
[svn] Removed ftpparse dependencies. New parser for VMS listings. MacOS
NetPresenz FTP sevber is now supported.
This commit is contained in:
parent
ccfe785e9e
commit
004b339d2e
119
src/ftp-basic.c
119
src/ftp-basic.c
@ -60,33 +60,33 @@ ftp_response (struct rbuf *rbuf, char **line)
|
||||
do
|
||||
{
|
||||
for (i = 0; 1; i++)
|
||||
{
|
||||
int res;
|
||||
if (i > bufsize - 1)
|
||||
*line = (char *)xrealloc (*line, (bufsize <<= 1));
|
||||
res = RBUF_READCHAR (rbuf, *line + i);
|
||||
/* RES is number of bytes read. */
|
||||
if (res == 1)
|
||||
{
|
||||
if ((*line)[i] == '\n')
|
||||
{
|
||||
(*line)[i] = '\0';
|
||||
/* Get rid of \r. */
|
||||
if (i > 0 && (*line)[i - 1] == '\r')
|
||||
(*line)[i - 1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
return FTPRERR;
|
||||
}
|
||||
{
|
||||
int res;
|
||||
if (i > bufsize - 1)
|
||||
*line = (char *)xrealloc (*line, (bufsize <<= 1));
|
||||
res = RBUF_READCHAR (rbuf, *line + i);
|
||||
/* RES is number of bytes read. */
|
||||
if (res == 1)
|
||||
{
|
||||
if ((*line)[i] == '\n')
|
||||
{
|
||||
(*line)[i] = '\0';
|
||||
/* Get rid of \r. */
|
||||
if (i > 0 && (*line)[i - 1] == '\r')
|
||||
(*line)[i - 1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
return FTPRERR;
|
||||
}
|
||||
if (opt.server_response)
|
||||
logprintf (LOG_ALWAYS, "%s\n", *line);
|
||||
logprintf (LOG_ALWAYS, "%s\n", *line);
|
||||
else
|
||||
DEBUGP (("%s\n", *line));
|
||||
DEBUGP (("%s\n", *line));
|
||||
}
|
||||
while (!(i >= 3 && ISDIGIT (**line) && ISDIGIT ((*line)[1]) &&
|
||||
ISDIGIT ((*line)[2]) && (*line)[3] == ' '));
|
||||
ISDIGIT ((*line)[2]) && (*line)[3] == ' '));
|
||||
strncpy (ftp_last_respline, *line, sizeof (ftp_last_respline));
|
||||
ftp_last_respline[sizeof (ftp_last_respline) - 1] = '\0';
|
||||
return FTPOK;
|
||||
@ -99,16 +99,16 @@ static char *
|
||||
ftp_request (const char *command, const char *value)
|
||||
{
|
||||
char *res = (char *)xmalloc (strlen (command)
|
||||
+ (value ? (1 + strlen (value)) : 0)
|
||||
+ 2 + 1);
|
||||
+ (value ? (1 + strlen (value)) : 0)
|
||||
+ 2 + 1);
|
||||
sprintf (res, "%s%s%s\r\n", command, value ? " " : "", value ? value : "");
|
||||
if (opt.server_response)
|
||||
{
|
||||
/* Hack: don't print out password. */
|
||||
if (strncmp (res, "PASS", 4) != 0)
|
||||
logprintf (LOG_ALWAYS, "--> %s\n", res);
|
||||
logprintf (LOG_ALWAYS, "--> %s\n", res);
|
||||
else
|
||||
logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n");
|
||||
logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n");
|
||||
}
|
||||
else
|
||||
DEBUGP (("\n--> %s\n", res));
|
||||
@ -179,31 +179,31 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass)
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE (skey_head); i++)
|
||||
{
|
||||
if (strncasecmp (skey_head[i], respline, strlen (skey_head[i])) == 0)
|
||||
break;
|
||||
if (strncasecmp (skey_head[i], respline, strlen (skey_head[i])) == 0)
|
||||
break;
|
||||
}
|
||||
if (i < ARRAY_SIZE (skey_head))
|
||||
{
|
||||
const char *cp;
|
||||
int skey_sequence = 0;
|
||||
const char *cp;
|
||||
int skey_sequence = 0;
|
||||
|
||||
for (cp = respline + strlen (skey_head[i]);
|
||||
'0' <= *cp && *cp <= '9';
|
||||
cp++)
|
||||
{
|
||||
skey_sequence = skey_sequence * 10 + *cp - '0';
|
||||
}
|
||||
if (*cp == ' ')
|
||||
cp++;
|
||||
else
|
||||
{
|
||||
bad:
|
||||
xfree (respline);
|
||||
return FTPLOGREFUSED;
|
||||
}
|
||||
if ((cp = calculate_skey_response (skey_sequence, cp, pass)) == 0)
|
||||
goto bad;
|
||||
pass = cp;
|
||||
for (cp = respline + strlen (skey_head[i]);
|
||||
'0' <= *cp && *cp <= '9';
|
||||
cp++)
|
||||
{
|
||||
skey_sequence = skey_sequence * 10 + *cp - '0';
|
||||
}
|
||||
if (*cp == ' ')
|
||||
cp++;
|
||||
else
|
||||
{
|
||||
bad:
|
||||
xfree (respline);
|
||||
return FTPLOGREFUSED;
|
||||
}
|
||||
if ((cp = calculate_skey_response (skey_sequence, cp, pass)) == 0)
|
||||
goto bad;
|
||||
pass = cp;
|
||||
}
|
||||
}
|
||||
#endif /* USE_OPIE */
|
||||
@ -258,8 +258,8 @@ ftp_port (struct rbuf *rbuf)
|
||||
/* Construct the argument of PORT (of the form a,b,c,d,e,f). */
|
||||
bytes = (char *)alloca (6 * 4 + 1);
|
||||
sprintf (bytes, "%d,%d,%d,%d,%d,%d", in_addr[0], in_addr[1],
|
||||
in_addr[2], in_addr[3], (unsigned) (port & 0xff00) >> 8,
|
||||
port & 0xff);
|
||||
in_addr[2], in_addr[3], (unsigned) (port & 0xff00) >> 8,
|
||||
port & 0xff);
|
||||
/* Send PORT request. */
|
||||
request = ftp_request ("PORT", bytes);
|
||||
nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
|
||||
@ -326,15 +326,15 @@ ftp_pasv (struct rbuf *rbuf, unsigned char *addr)
|
||||
{
|
||||
addr[i] = 0;
|
||||
for (; ISDIGIT (*s); s++)
|
||||
addr[i] = (*s - '0') + 10 * addr[i];
|
||||
addr[i] = (*s - '0') + 10 * addr[i];
|
||||
if (*s == ',')
|
||||
s++;
|
||||
s++;
|
||||
else if (i < 5)
|
||||
{
|
||||
/* When on the last number, anything can be a terminator. */
|
||||
xfree (respline);
|
||||
return FTPINVPASV;
|
||||
}
|
||||
{
|
||||
/* When on the last number, anything can be a terminator. */
|
||||
xfree (respline);
|
||||
return FTPINVPASV;
|
||||
}
|
||||
}
|
||||
xfree (respline);
|
||||
return FTPOK;
|
||||
@ -578,7 +578,10 @@ ftp_syst (struct rbuf *rbuf, enum stype *server_type)
|
||||
if (!strcasecmp (request, "WINDOWS_NT"))
|
||||
*server_type = ST_WINNT;
|
||||
else
|
||||
*server_type = ST_OTHER;
|
||||
if (!strcasecmp (request, "MACOS"))
|
||||
*server_type = ST_MACOS;
|
||||
else
|
||||
*server_type = ST_OTHER;
|
||||
|
||||
xfree (respline);
|
||||
/* All OK. */
|
||||
|
308
src/ftp-ls.c
308
src/ftp-ls.c
@ -1,5 +1,6 @@
|
||||
/* Parsing FTP `ls' output.
|
||||
Copyright (C) 1995, 1996, 1997, 2000 Free Software Foundation, Inc.
|
||||
Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This file is part of Wget.
|
||||
|
||||
@ -38,15 +39,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
#include "ftp.h"
|
||||
#include "url.h"
|
||||
|
||||
/* Undef this if FTPPARSE is not available. In that case, Wget will
|
||||
still work with Unix FTP servers, which covers most cases. */
|
||||
|
||||
#define HAVE_FTPPARSE
|
||||
|
||||
#ifdef HAVE_FTPPARSE
|
||||
#include "ftpparse.h"
|
||||
#endif
|
||||
|
||||
/* Converts symbolic permissions to number-style ones, e.g. string
|
||||
rwxr-xr-x to 755. For now, it knows nothing of
|
||||
setuid/setgid/sticky. ACLs are ignored. */
|
||||
@ -67,6 +59,23 @@ symperms (const char *s)
|
||||
}
|
||||
|
||||
|
||||
/* Cleans a line of text so that it can be consistently parsed. Destroys
|
||||
<CR> and <LF> in case that thay occur at the end of the line and
|
||||
replaces all <TAB> character with <SPACE>. Returns the length of the
|
||||
modified line. */
|
||||
static int
|
||||
clean_line(char *line)
|
||||
{
|
||||
int len = strlen (line);
|
||||
if (!len) return 0;
|
||||
if (line[len - 1] == '\n')
|
||||
line[--len] = '\0';
|
||||
if (line[len - 1] == '\r')
|
||||
line[--len] = '\0';
|
||||
for ( ; *line ; line++ ) if (*line == '\t') *line = ' ';
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Convert the Un*x-ish style directory listing stored in FILE to a
|
||||
linked list of fileinfo (system-independent) entries. The contents
|
||||
of FILE are considered to be produced by the standard Unix `ls -la'
|
||||
@ -103,14 +112,7 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
|
||||
/* Line loop to end of file: */
|
||||
while ((line = read_whole_line (fp)))
|
||||
{
|
||||
DEBUGP (("%s\n", line));
|
||||
len = strlen (line);
|
||||
/* Destroy <CR><LF> if present. */
|
||||
if (len && line[len - 1] == '\n')
|
||||
line[--len] = '\0';
|
||||
if (len && line[len - 1] == '\r')
|
||||
line[--len] = '\0';
|
||||
|
||||
len = clean_line (line);
|
||||
/* Skip if total... */
|
||||
if (!strncasecmp (line, "total", 5))
|
||||
{
|
||||
@ -426,13 +428,7 @@ ftp_parse_winnt_ls (const char *file)
|
||||
/* Line loop to end of file: */
|
||||
while ((line = read_whole_line (fp)))
|
||||
{
|
||||
DEBUGP (("%s\n", line));
|
||||
len = strlen (line);
|
||||
/* Destroy <CR><LF> if present. */
|
||||
if (len && line[len - 1] == '\n')
|
||||
line[--len] = '\0';
|
||||
if (len && line[len - 1] == '\r')
|
||||
line[--len] = '\0';
|
||||
len = clean_line (line);
|
||||
|
||||
/* Extracting name is a bit of black magic and we have to do it
|
||||
before `strtok' inserted extra \0 characters in the line
|
||||
@ -529,20 +525,45 @@ ftp_parse_winnt_ls (const char *file)
|
||||
return dir;
|
||||
}
|
||||
|
||||
/* Converts VMS symbolic permissions to number-style ones, e.g. string
|
||||
RWED,RWE,RE to 755. "D" (delete) is taken to be equal to "W"
|
||||
(write). Inspired by a patch of Stoyan Lekov <lekov@eda.bg>. */
|
||||
static int
|
||||
vmsperms (const char *s)
|
||||
{
|
||||
int perms = 0;
|
||||
|
||||
#ifdef HAVE_FTPPARSE
|
||||
do
|
||||
{
|
||||
switch (*s) {
|
||||
case ',': perms <<= 3; break;
|
||||
case 'R': perms |= 4; break;
|
||||
case 'W': perms |= 2; break;
|
||||
case 'D': perms |= 2; break;
|
||||
case 'E': perms |= 1; break;
|
||||
default: DEBUGP(("wrong VMS permissons!\n"));
|
||||
}
|
||||
}
|
||||
while (*++s);
|
||||
return perms;
|
||||
}
|
||||
|
||||
/* This is a "glue function" that connects the ftpparse interface to
|
||||
the interface Wget expects. ftpparse is used to parse listings
|
||||
from servers other than Unix, like those running VMS or NT. */
|
||||
|
||||
static struct fileinfo *
|
||||
ftp_parse_nonunix_ls (const char *file)
|
||||
ftp_parse_vms_ls (const char *file)
|
||||
{
|
||||
FILE *fp;
|
||||
int len;
|
||||
/* #### A third copy of more-or-less the same array ? */
|
||||
static const char *months[] = {
|
||||
"JAN", "FEB", "MAR", "APR", "MAY", "JUN",
|
||||
"JUL", "AUG", "SEP", "OCT", "NOV", "DEC"
|
||||
};
|
||||
int i;
|
||||
int year, month, day; /* for time analysis */
|
||||
int hour, min, sec;
|
||||
struct tm timestruct;
|
||||
|
||||
char *line; /* tokenizer */
|
||||
char *line, *tok, *p; /* tokenizer */
|
||||
struct fileinfo *dir, *l, cur; /* list creation */
|
||||
|
||||
fp = fopen (file, "rb");
|
||||
@ -553,56 +574,161 @@ ftp_parse_nonunix_ls (const char *file)
|
||||
}
|
||||
dir = l = NULL;
|
||||
|
||||
/* Empty line */
|
||||
read_whole_line (fp);
|
||||
/* "Directory PUB$DEVICE[PUB]" */
|
||||
read_whole_line (fp);
|
||||
/* Empty line */
|
||||
read_whole_line (fp);
|
||||
|
||||
/* Line loop to end of file: */
|
||||
while ((line = read_whole_line (fp)))
|
||||
{
|
||||
struct ftpparse fp;
|
||||
i = clean_line (line);
|
||||
if (!i) break;
|
||||
|
||||
DEBUGP (("%s\n", line));
|
||||
len = strlen (line);
|
||||
/* Destroy <CR><LF> if present. */
|
||||
if (len && line[len - 1] == '\n')
|
||||
line[--len] = '\0';
|
||||
if (len && line[len - 1] == '\r')
|
||||
line[--len] = '\0';
|
||||
/* First column: Name. A bit of black magic again. The name my be
|
||||
either ABCD.EXT or ABCD.EXT;NUM and it might be on a separate
|
||||
line. Therefore we will first try to get the complete name
|
||||
until the first space character; if it fails, we assume that the name
|
||||
occupies the whole line. After that we search for the version
|
||||
separator ";", we remove it and check the extension of the file;
|
||||
extension .DIR denotes directory. */
|
||||
|
||||
if (ftpparse(&fp, line, len))
|
||||
tok = strtok(line, " ");
|
||||
if (tok == NULL) tok = line;
|
||||
DEBUGP(("file name: '%s'\n", tok));
|
||||
for (p = tok ; *p && *p != ';' ; p++);
|
||||
if (*p == ';') *p = '\0';
|
||||
p = tok + strlen(tok) - 4;
|
||||
if (!strcmp(p, ".DIR")) *p = '\0';
|
||||
cur.name = xstrdup(tok);
|
||||
DEBUGP(("Name: '%s'\n", cur.name));
|
||||
|
||||
/* If the name ends on .DIR or .DIR;#, it's a directory. We also set
|
||||
the file size to zero as the listing does tell us only the size in
|
||||
filesystem blocks - for an integrity check (when mirroring, for
|
||||
example) we would need the size in bytes. */
|
||||
|
||||
if (! *p)
|
||||
{
|
||||
cur.size = fp.size;
|
||||
cur.name = (char *)xmalloc (fp.namelen + 1);
|
||||
memcpy (cur.name, fp.name, fp.namelen);
|
||||
cur.name[fp.namelen] = '\0';
|
||||
DEBUGP (("%s\n", cur.name));
|
||||
/* No links on non-UNIX systems */
|
||||
cur.linkto = NULL;
|
||||
/* ftpparse won't tell us correct permisions. So lets just invent
|
||||
something. */
|
||||
if (fp.flagtrycwd)
|
||||
{
|
||||
cur.type = FT_DIRECTORY;
|
||||
cur.perms = 0755;
|
||||
}
|
||||
else
|
||||
{
|
||||
cur.type = FT_PLAINFILE;
|
||||
cur.perms = 0644;
|
||||
}
|
||||
if (!dir)
|
||||
{
|
||||
l = dir = (struct fileinfo *)xmalloc (sizeof (struct fileinfo));
|
||||
memcpy (l, &cur, sizeof (cur));
|
||||
l->prev = l->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
cur.prev = l;
|
||||
l->next = (struct fileinfo *)xmalloc (sizeof (struct fileinfo));
|
||||
l = l->next;
|
||||
memcpy (l, &cur, sizeof (cur));
|
||||
l->next = NULL;
|
||||
}
|
||||
l->tstamp = fp.mtime;
|
||||
cur.type = FT_DIRECTORY;
|
||||
cur.size = 0;
|
||||
DEBUGP(("Directory\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
cur.type = FT_PLAINFILE;
|
||||
DEBUGP(("File\n"));
|
||||
}
|
||||
|
||||
cur.size = 0;
|
||||
|
||||
/* Second column, if exists, or the first column of the next line
|
||||
contain file size in blocks. We will skip it. */
|
||||
|
||||
tok = strtok(NULL, " ");
|
||||
if (tok == NULL)
|
||||
{
|
||||
DEBUGP(("Getting additional line\n"));
|
||||
xfree (line);
|
||||
line = read_whole_line (fp);
|
||||
if (!line)
|
||||
{
|
||||
DEBUGP(("empty line read, leaving listing parser\n"));
|
||||
break;
|
||||
}
|
||||
i = clean_line (line);
|
||||
if (!i)
|
||||
{
|
||||
DEBUGP(("confusing VMS listing item, leaving listing parser\n"));
|
||||
break;
|
||||
}
|
||||
tok = strtok(line, " ");
|
||||
}
|
||||
DEBUGP(("second token: '%s'\n", tok));
|
||||
|
||||
/* Third/Second column: Date DD-MMM-YYYY. */
|
||||
|
||||
tok = strtok(NULL, "-");
|
||||
DEBUGP(("day: '%s'\n",tok));
|
||||
day = atoi(tok);
|
||||
tok = strtok(NULL, "-");
|
||||
if (!tok)
|
||||
{
|
||||
/* If the server produces garbage like
|
||||
'EA95_0PS.GZ;1 No privilege for attempted operation'
|
||||
the first strtok(NULL, "-") will return everything until the end
|
||||
of the line and only the next strtok() call will return NULL. */
|
||||
DEBUGP(("nonsense in VMS listing, skipping this line\n"));
|
||||
break;
|
||||
}
|
||||
for (i=0; i<12; i++) if (!strcmp(tok,months[i])) break;
|
||||
/* Uknown months are mapped to January */
|
||||
month = (i%12)+1;
|
||||
tok = strtok(NULL, " ");
|
||||
year = atoi(tok)-1900;
|
||||
DEBUGP(("date parsed\n"));
|
||||
|
||||
/* Fourth/Third column: Time hh:mm:ss */
|
||||
tok = strtok(NULL, ":");
|
||||
hour = atoi(tok);
|
||||
tok = strtok(NULL, ":");
|
||||
min = atoi(tok);
|
||||
tok = strtok(NULL, " ");
|
||||
sec = atoi(tok);
|
||||
|
||||
DEBUGP(("YYYY/MM/DD HH:MM:SS - %d/%02d/%02d %02d:%02d:%02d\n",
|
||||
year+1900, month, day, hour, min, sec));
|
||||
|
||||
/* Build the time-stamp (copy & paste from above) */
|
||||
timestruct.tm_sec = sec;
|
||||
timestruct.tm_min = min;
|
||||
timestruct.tm_hour = hour;
|
||||
timestruct.tm_mday = day;
|
||||
timestruct.tm_mon = month;
|
||||
timestruct.tm_year = year;
|
||||
timestruct.tm_wday = 0;
|
||||
timestruct.tm_yday = 0;
|
||||
timestruct.tm_isdst = -1;
|
||||
cur.tstamp = mktime (×truct); /* store the time-stamp */
|
||||
|
||||
DEBUGP(("Timestamp: %ld\n", cur.tstamp));
|
||||
|
||||
/* Skip the fifth column */
|
||||
|
||||
tok = strtok(NULL, " ");
|
||||
|
||||
/* Sixth column: Permissions */
|
||||
|
||||
tok = strtok(NULL, ","); /* Skip the VMS-specific SYSTEM permissons */
|
||||
tok = strtok(NULL, ")");
|
||||
if (tok == NULL)
|
||||
{
|
||||
DEBUGP(("confusing VMS permissions, skipping line\n"));
|
||||
continue;
|
||||
}
|
||||
/* Permissons have the format "RWED,RWED,RE" */
|
||||
cur.perms = vmsperms(tok);
|
||||
DEBUGP(("permissions: %s -> 0%o\n", tok, cur.perms));
|
||||
|
||||
cur.linkto = NULL;
|
||||
|
||||
/* And put everything into the linked list */
|
||||
if (!dir)
|
||||
{
|
||||
l = dir = (struct fileinfo *)xmalloc (sizeof (struct fileinfo));
|
||||
memcpy (l, &cur, sizeof (cur));
|
||||
l->prev = l->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
cur.prev = l;
|
||||
l->next = (struct fileinfo *)xmalloc (sizeof (struct fileinfo));
|
||||
l = l->next;
|
||||
memcpy (l, &cur, sizeof (cur));
|
||||
l->next = NULL;
|
||||
}
|
||||
|
||||
xfree (line);
|
||||
}
|
||||
@ -610,14 +736,13 @@ ftp_parse_nonunix_ls (const char *file)
|
||||
fclose (fp);
|
||||
return dir;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This function switches between the correct parsing routine
|
||||
depending on the SYSTEM_TYPE. If system type is ST_UNIX, we use
|
||||
our home-grown ftp_parse_unix_ls; otherwise, we use our interface
|
||||
to ftpparse, also known as ftp_parse_nonunix_ls. The system type
|
||||
should be based on the result of the "SYST" response of the FTP
|
||||
server. */
|
||||
|
||||
/* This function switches between the correct parsing routine depending on
|
||||
the SYSTEM_TYPE. The system type should be based on the result of the
|
||||
"SYST" response of the FTP server. According to this repsonse we will
|
||||
use on of the three different listing parsers that cover the most of FTP
|
||||
servers used nowadays. */
|
||||
|
||||
struct fileinfo *
|
||||
ftp_parse_ls (const char *file, const enum stype system_type)
|
||||
@ -636,23 +761,24 @@ ftp_parse_ls (const char *file, const enum stype system_type)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
c = fgetc(fp);
|
||||
fclose(fp);
|
||||
/* If the first character of the file is '0'-'9', it's WINNT
|
||||
format. */
|
||||
if (c >= '0' && c <='9')
|
||||
return ftp_parse_winnt_ls (file);
|
||||
else
|
||||
return ftp_parse_unix_ls (file, TRUE);
|
||||
else
|
||||
return ftp_parse_unix_ls (file, TRUE);
|
||||
}
|
||||
case ST_VMS:
|
||||
return ftp_parse_vms_ls (file);
|
||||
case ST_MACOS:
|
||||
return ftp_parse_unix_ls (file, TRUE);
|
||||
default:
|
||||
#ifdef HAVE_FTPPARSE
|
||||
return ftp_parse_nonunix_ls (file);
|
||||
#else
|
||||
/* #### Maybe log some warning here? */
|
||||
return ftp_parse_unix_ls (file);
|
||||
#endif
|
||||
logprintf (LOG_NOTQUIET, _("\
|
||||
Usupported listing type, trying Unix listing parser.\n"));
|
||||
return ftp_parse_unix_ls (file, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
82
src/ftp.c
82
src/ftp.c
@ -62,12 +62,6 @@ extern int h_errno;
|
||||
|
||||
extern char ftp_last_respline[];
|
||||
|
||||
/* #### Global variables?? These two should be members of struct
|
||||
ccon! */
|
||||
|
||||
static enum stype host_type=ST_UNIX;
|
||||
static char *pwd;
|
||||
|
||||
/* Look for regexp "( *[0-9]+ *byte" (literal parenthesis) anywhere in
|
||||
the string S, and return the number converted to long, if found, 0
|
||||
otherwise. */
|
||||
@ -114,7 +108,7 @@ ftp_expected_bytes (const char *s)
|
||||
connection to the server. It always closes the data connection,
|
||||
and closes the control connection in case of error. */
|
||||
static uerr_t
|
||||
getftp (const struct urlinfo *u, long *len, long restval, ccon *con)
|
||||
getftp (struct urlinfo *u, long *len, long restval, ccon *con)
|
||||
{
|
||||
int csock, dtsock, res;
|
||||
uerr_t err;
|
||||
@ -254,7 +248,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, &host_type);
|
||||
err = ftp_syst (&con->rbuf, &con->rs);
|
||||
/* FTPRERR */
|
||||
switch (err)
|
||||
{
|
||||
@ -285,7 +279,7 @@ Error in server response, closing control connection.\n"));
|
||||
|
||||
if (!opt.server_response)
|
||||
logprintf (LOG_VERBOSE, "==> PWD ... ");
|
||||
err = ftp_pwd(&con->rbuf, &pwd);
|
||||
err = ftp_pwd(&con->rbuf, &con->id);
|
||||
/* FTPRERR */
|
||||
switch (err)
|
||||
{
|
||||
@ -361,10 +355,10 @@ Error in server response, closing control connection.\n"));
|
||||
DEBUGP (("changing working directory\n"));
|
||||
if (*(u->dir) == '/')
|
||||
{
|
||||
int pwd_len = strlen (pwd);
|
||||
int pwd_len = strlen (con->id);
|
||||
char *result = (char *)alloca (strlen (u->dir) + pwd_len + 10);
|
||||
*result = '\0';
|
||||
switch (host_type)
|
||||
switch (con->rs)
|
||||
{
|
||||
case ST_VMS:
|
||||
{
|
||||
@ -373,7 +367,7 @@ Error in server response, closing control connection.\n"));
|
||||
for (tmpp = tmp_dir; *tmpp; tmpp++)
|
||||
if (*tmpp=='/')
|
||||
*tmpp = '.';
|
||||
strcpy (result, pwd);
|
||||
strcpy (result, con->id);
|
||||
/* pwd ends with ']', we have to get rid of it */
|
||||
result[pwd_len - 1]= '\0';
|
||||
strcat (result, tmp_dir);
|
||||
@ -382,16 +376,14 @@ Error in server response, closing control connection.\n"));
|
||||
break;
|
||||
case ST_UNIX:
|
||||
case ST_WINNT:
|
||||
case ST_MACOS:
|
||||
/* pwd_len == 1 means pwd = "/", but u->dir begins with '/'
|
||||
already */
|
||||
if (pwd_len > 1)
|
||||
strcpy (result, pwd);
|
||||
strcpy (result, con->id);
|
||||
strcat (result, u->dir);
|
||||
/* These look like debugging messages to me. */
|
||||
#if 0
|
||||
logprintf (LOG_VERBOSE, "\npwd=\"%s\"", pwd);
|
||||
logprintf (LOG_VERBOSE, "\nu->dir=\"%s\"", u->dir);
|
||||
#endif
|
||||
DEBUGP(("\npwd=\"%s\"", con->id));
|
||||
DEBUGP(("\nu->dir=\"%s\"", u->dir));
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
@ -1177,7 +1169,7 @@ ftp_get_listing (struct urlinfo *u, ccon *con)
|
||||
err = ftp_loop_internal (u, NULL, con);
|
||||
u->local = olocal;
|
||||
if (err == RETROK)
|
||||
f = ftp_parse_ls (list_filename, host_type);
|
||||
f = ftp_parse_ls (list_filename, con->rs);
|
||||
else
|
||||
f = NULL;
|
||||
if (opt.remove_listing)
|
||||
@ -1259,7 +1251,7 @@ ftp_retrieve_list (struct urlinfo *u, struct fileinfo *f, ccon *con)
|
||||
|
||||
dlthis = 1;
|
||||
if (opt.timestamping && f->type == FT_PLAINFILE)
|
||||
{
|
||||
{
|
||||
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.
|
||||
@ -1268,30 +1260,38 @@ ftp_retrieve_list (struct urlinfo *u, struct fileinfo *f, ccon *con)
|
||||
.orig suffix. */
|
||||
if (!stat (u->local, &st))
|
||||
{
|
||||
int eq_size;
|
||||
int cor_val;
|
||||
/* Else, get it from the file. */
|
||||
local_size = st.st_size;
|
||||
tml = st.st_mtime;
|
||||
if (local_size == f->size && tml >= f->tstamp)
|
||||
/* Compare file sizes only for servers that tell us correct
|
||||
values. Assumme sizes being equal for servers that lie
|
||||
about file size. */
|
||||
cor_val = (con->rs == ST_UNIX || con->rs == ST_WINNT);
|
||||
eq_size = cor_val ? (local_size == f->size) : 1 ;
|
||||
if (f->tstamp <= tml && eq_size)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, _("\
|
||||
Server file no newer than local file `%s' -- not retrieving.\n\n"), u->local);
|
||||
/* Remote file is older, file sizes can be compared and
|
||||
are both equal. */
|
||||
logprintf (LOG_VERBOSE, _("\
|
||||
Remote file no newer than local file `%s' -- not retrieving.\n"), u->local);
|
||||
dlthis = 0;
|
||||
}
|
||||
else if (local_size != f->size)
|
||||
{
|
||||
if (host_type == ST_VMS)
|
||||
{
|
||||
logprintf (LOG_VERBOSE, _("\
|
||||
Cannot compare sizes, remote system is VMS.\n"));
|
||||
dlthis = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
logprintf (LOG_VERBOSE, _("\
|
||||
The sizes do not match (local %ld) -- retrieving.\n"), local_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (eq_size)
|
||||
{
|
||||
/* Remote file is newer or sizes cannot be matched */
|
||||
logprintf (LOG_VERBOSE, _("\
|
||||
Remote file is newer than local file `%s' -- retrieving.\n\n"),
|
||||
u->local);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Sizes do not match */
|
||||
logprintf (LOG_VERBOSE, _("\
|
||||
The sizes do not match (local %ld) -- retrieving.\n\n"), local_size);
|
||||
}
|
||||
}
|
||||
} /* opt.timestamping && f->type == FT_PLAINFILE */
|
||||
switch (f->type)
|
||||
{
|
||||
@ -1571,6 +1571,8 @@ ftp_loop (struct urlinfo *u, int *dt)
|
||||
|
||||
rbuf_uninitialize (&con.rbuf);
|
||||
con.st = ON_YOUR_OWN;
|
||||
con.rs = ST_UNIX;
|
||||
con.id = NULL;
|
||||
res = RETROK; /* in case it's not used */
|
||||
|
||||
/* If the file name is empty, the user probably wants a directory
|
||||
@ -1634,8 +1636,8 @@ ftp_loop (struct urlinfo *u, int *dt)
|
||||
/* If a connection was left, quench it. */
|
||||
if (rbuf_initialized_p (&con.rbuf))
|
||||
CLOSE (RBUF_FD (&con.rbuf));
|
||||
FREE_MAYBE (pwd);
|
||||
pwd = NULL;
|
||||
FREE_MAYBE (con.id);
|
||||
con.id = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ enum stype
|
||||
ST_UNIX,
|
||||
ST_VMS,
|
||||
ST_WINNT,
|
||||
ST_MACOS,
|
||||
ST_OTHER
|
||||
};
|
||||
|
||||
@ -98,6 +99,8 @@ typedef struct
|
||||
int cmd; /* command code */
|
||||
struct rbuf rbuf; /* control connection buffer */
|
||||
long dltime; /* time of the download */
|
||||
enum stype rs; /* remote system reported by ftp server */
|
||||
char *id; /* initial directory */
|
||||
} ccon;
|
||||
|
||||
struct fileinfo *ftp_parse_ls PARAMS ((const char *, enum stype));
|
||||
|
Loading…
Reference in New Issue
Block a user