Merge libfetch-2.30 from NetBSD's pkgsrc.
--HG-- extra : convert_revision : xtraeme%40gmail.com-20100124144753-ni487x8m7r05847b
This commit is contained in:
161
lib/fetch/ftp.c
161
lib/fetch/ftp.c
@ -1,7 +1,7 @@
|
||||
/* $NetBSD: ftp.c,v 1.30 2009/10/15 12:36:57 joerg Exp $ */
|
||||
/* $NetBSD: ftp.c,v 1.34 2010/01/23 14:25:26 joerg Exp $ */
|
||||
/*-
|
||||
* Copyright (c) 1998-2004 Dag-Erling Coïdan Smørav
|
||||
* Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org>
|
||||
* Copyright (c) 1998-2004 Dag-Erling Co<EFBFBD>dan Sm<EFBFBD>rgrav
|
||||
* Copyright (c) 2008, 2009, 2010 Joerg Sonnenberger <joerg@NetBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -115,9 +115,6 @@
|
||||
#define FTP_SYNTAX_ERROR 500
|
||||
#define FTP_PROTOCOL_ERROR 999
|
||||
|
||||
static struct url cached_host;
|
||||
static conn_t *cached_connection;
|
||||
|
||||
#define isftpreply(foo) \
|
||||
(isdigit((unsigned char)foo[0]) && \
|
||||
isdigit((unsigned char)foo[1]) && \
|
||||
@ -212,7 +209,7 @@ ftp_cmd(conn_t *conn, const char *fmt, ...)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
r = fetch_putln(conn, msg, len);
|
||||
r = fetch_write(conn, msg, len);
|
||||
free(msg);
|
||||
|
||||
if (r == -1) {
|
||||
@ -294,7 +291,7 @@ ftp_cwd(conn_t *conn, const char *file, int subdir)
|
||||
end = file + strlen(file);
|
||||
else if ((end = strrchr(file, '/')) == NULL)
|
||||
return (0);
|
||||
if ((e = ftp_cmd(conn, "PWD")) != FTP_WORKING_DIRECTORY ||
|
||||
if ((e = ftp_cmd(conn, "PWD\r\n")) != FTP_WORKING_DIRECTORY ||
|
||||
(e = ftp_pwd(conn, pwd, sizeof(pwd))) != FTP_OK) {
|
||||
ftp_seterr(e);
|
||||
return (-1);
|
||||
@ -311,8 +308,8 @@ ftp_cwd(conn_t *conn, const char *file, int subdir)
|
||||
break;
|
||||
if (pwd[i] == '\0' && (file[i - 1] == '/' || file[i] == '/'))
|
||||
break;
|
||||
if ((e = ftp_cmd(conn, "CDUP")) != FTP_FILE_ACTION_OK ||
|
||||
(e = ftp_cmd(conn, "PWD")) != FTP_WORKING_DIRECTORY ||
|
||||
if ((e = ftp_cmd(conn, "CDUP\r\n")) != FTP_FILE_ACTION_OK ||
|
||||
(e = ftp_cmd(conn, "PWD\r\n")) != FTP_WORKING_DIRECTORY ||
|
||||
(e = ftp_pwd(conn, pwd, sizeof(pwd))) != FTP_OK) {
|
||||
ftp_seterr(e);
|
||||
return (-1);
|
||||
@ -329,7 +326,7 @@ ftp_cwd(conn_t *conn, const char *file, int subdir)
|
||||
return (0);
|
||||
|
||||
/* Change to the directory all in one chunk (e.g., foo/bar/baz). */
|
||||
e = ftp_cmd(conn, "CWD %.*s", (int)(end - beg), beg);
|
||||
e = ftp_cmd(conn, "CWD %.*s\r\n", (int)(end - beg), beg);
|
||||
if (e == FTP_FILE_ACTION_OK)
|
||||
return (0);
|
||||
#endif /* FTP_COMBINE_CWDS */
|
||||
@ -340,7 +337,7 @@ ftp_cwd(conn_t *conn, const char *file, int subdir)
|
||||
++beg, ++i;
|
||||
for (++i; file + i < end && file[i] != '/'; ++i)
|
||||
/* nothing */ ;
|
||||
e = ftp_cmd(conn, "CWD %.*s", file + i - beg, beg);
|
||||
e = ftp_cmd(conn, "CWD %.*s\r\n", file + i - beg, beg);
|
||||
if (e != FTP_FILE_ACTION_OK) {
|
||||
ftp_seterr(e);
|
||||
return (-1);
|
||||
@ -366,7 +363,7 @@ ftp_mode_type(conn_t *conn, int mode, int type)
|
||||
default:
|
||||
return (FTP_PROTOCOL_ERROR);
|
||||
}
|
||||
if ((e = ftp_cmd(conn, "MODE %c", mode)) != FTP_OK) {
|
||||
if ((e = ftp_cmd(conn, "MODE %c\r\n", mode)) != FTP_OK) {
|
||||
if (mode == 'S') {
|
||||
/*
|
||||
* Stream mode is supposed to be the default - so
|
||||
@ -402,7 +399,7 @@ ftp_mode_type(conn_t *conn, int mode, int type)
|
||||
default:
|
||||
return (FTP_PROTOCOL_ERROR);
|
||||
}
|
||||
if ((e = ftp_cmd(conn, "TYPE %c", type)) != FTP_OK)
|
||||
if ((e = ftp_cmd(conn, "TYPE %c\r\n", type)) != FTP_OK)
|
||||
return (e);
|
||||
|
||||
return (FTP_OK);
|
||||
@ -431,7 +428,7 @@ ftp_stat(conn_t *conn, const char *file, struct url_stat *us)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
e = ftp_cmd(conn, "SIZE %.*s", filenamelen, filename);
|
||||
e = ftp_cmd(conn, "SIZE %.*s\r\n", filenamelen, filename);
|
||||
if (e != FTP_FILE_STATUS) {
|
||||
ftp_seterr(e);
|
||||
return (-1);
|
||||
@ -448,7 +445,7 @@ ftp_stat(conn_t *conn, const char *file, struct url_stat *us)
|
||||
if (us->size == 0)
|
||||
us->size = -1;
|
||||
|
||||
e = ftp_cmd(conn, "MDTM %.*s", filenamelen, filename);
|
||||
e = ftp_cmd(conn, "MDTM %.*s\r\n", filenamelen, filename);
|
||||
if (e != FTP_FILE_STATUS) {
|
||||
ftp_seterr(e);
|
||||
return (-1);
|
||||
@ -560,6 +557,13 @@ ftp_writefn(void *v, const void *buf, size_t len)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static int
|
||||
ftp_disconnect(conn_t *conn)
|
||||
{
|
||||
ftp_cmd(conn, "QUIT\r\n");
|
||||
return fetch_close(conn);
|
||||
}
|
||||
|
||||
static void
|
||||
ftp_closefn(void *v)
|
||||
{
|
||||
@ -578,15 +582,10 @@ ftp_closefn(void *v)
|
||||
return;
|
||||
}
|
||||
fetch_close(io->dconn);
|
||||
io->dir = -1;
|
||||
io->dconn->is_active = 0;
|
||||
io->dconn = NULL;
|
||||
io->dir = -1;
|
||||
r = ftp_chkerr(io->cconn);
|
||||
if (io->cconn == cached_connection && io->cconn->ref == 1) {
|
||||
free(cached_host.doc);
|
||||
cached_connection = NULL;
|
||||
}
|
||||
fetch_close(io->cconn);
|
||||
fetch_cache_put(io->cconn, ftp_disconnect);
|
||||
free(io);
|
||||
return;
|
||||
}
|
||||
@ -605,7 +604,6 @@ ftp_setup(conn_t *cconn, conn_t *dconn, int mode)
|
||||
io->dconn = dconn;
|
||||
io->dir = mode;
|
||||
io->eof = io->err = 0;
|
||||
io->cconn->is_active = 1;
|
||||
f = fetchIO_unopen(io, ftp_readfn, ftp_writefn, ftp_closefn);
|
||||
if (f == NULL)
|
||||
free(io);
|
||||
@ -677,14 +675,14 @@ retry_mode:
|
||||
fetch_info("setting passive mode");
|
||||
switch (u.ss.ss_family) {
|
||||
case AF_INET:
|
||||
if ((e = ftp_cmd(conn, "PASV")) != FTP_PASSIVE_MODE)
|
||||
if ((e = ftp_cmd(conn, "PASV\r\n")) != FTP_PASSIVE_MODE)
|
||||
goto ouch;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if ((e = ftp_cmd(conn, "EPSV")) != FTP_EPASSIVE_MODE) {
|
||||
if ((e = ftp_cmd(conn, "EPSV\r\n")) != FTP_EPASSIVE_MODE) {
|
||||
if (e == -1)
|
||||
goto ouch;
|
||||
if ((e = ftp_cmd(conn, "LPSV")) !=
|
||||
if ((e = ftp_cmd(conn, "LPSV\r\n")) !=
|
||||
FTP_LPASSIVE_MODE)
|
||||
goto ouch;
|
||||
}
|
||||
@ -744,7 +742,7 @@ retry_mode:
|
||||
|
||||
/* seek to required offset */
|
||||
if (offset)
|
||||
if (ftp_cmd(conn, "REST %lu", (unsigned long)offset) != FTP_FILE_OK)
|
||||
if (ftp_cmd(conn, "REST %lu\r\n", (unsigned long)offset) != FTP_FILE_OK)
|
||||
goto sysouch;
|
||||
|
||||
/* construct sockaddr for data socket */
|
||||
@ -789,9 +787,9 @@ retry_mode:
|
||||
if (verbose)
|
||||
fetch_info("initiating transfer");
|
||||
if (op_arg)
|
||||
e = ftp_cmd(conn, "%s%s%s", oper, *op_arg ? " " : "", op_arg);
|
||||
e = ftp_cmd(conn, "%s%s%s\r\n", oper, *op_arg ? " " : "", op_arg);
|
||||
else
|
||||
e = ftp_cmd(conn, "%s %.*s", oper,
|
||||
e = ftp_cmd(conn, "%s %.*s\r\n", oper,
|
||||
filenamelen, filename);
|
||||
if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION)
|
||||
goto ouch;
|
||||
@ -840,7 +838,7 @@ retry_mode:
|
||||
case AF_INET:
|
||||
a = ntohl(u.sin4.sin_addr.s_addr);
|
||||
p = ntohs(u.sin4.sin_port);
|
||||
e = ftp_cmd(conn, "PORT %d,%d,%d,%d,%d,%d",
|
||||
e = ftp_cmd(conn, "PORT %d,%d,%d,%d,%d,%d\r\n",
|
||||
(a >> 24) & 0xff, (a >> 16) & 0xff,
|
||||
(a >> 8) & 0xff, a & 0xff,
|
||||
(p >> 8) & 0xff, p & 0xff);
|
||||
@ -852,7 +850,7 @@ retry_mode:
|
||||
if (getnameinfo(&u.sa, l,
|
||||
hname, sizeof(hname),
|
||||
NULL, 0, NI_NUMERICHOST) == 0) {
|
||||
e = ftp_cmd(conn, "EPRT |%d|%s|%d|", 2, hname,
|
||||
e = ftp_cmd(conn, "EPRT |%d|%s|%d|\r\n", 2, hname,
|
||||
htons(u.sin6.sin6_port));
|
||||
if (e == -1)
|
||||
goto ouch;
|
||||
@ -860,7 +858,7 @@ retry_mode:
|
||||
if (e != FTP_OK) {
|
||||
ap = (char *)&u.sin6.sin6_addr;
|
||||
e = ftp_cmd(conn,
|
||||
"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
|
||||
"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n",
|
||||
6, 16,
|
||||
UC(ap[0]), UC(ap[1]), UC(ap[2]), UC(ap[3]),
|
||||
UC(ap[4]), UC(ap[5]), UC(ap[6]), UC(ap[7]),
|
||||
@ -880,16 +878,16 @@ retry_mode:
|
||||
|
||||
/* seek to required offset */
|
||||
if (offset)
|
||||
if (ftp_cmd(conn, "REST %llu", (unsigned long long)offset) != FTP_FILE_OK)
|
||||
if (ftp_cmd(conn, "REST %llu\r\n", (unsigned long long)offset) != FTP_FILE_OK)
|
||||
goto sysouch;
|
||||
|
||||
/* make the server initiate the transfer */
|
||||
if (verbose)
|
||||
fetch_info("initiating transfer");
|
||||
if (op_arg)
|
||||
e = ftp_cmd(conn, "%s%s%s", oper, *op_arg ? " " : "", op_arg);
|
||||
e = ftp_cmd(conn, "%s%s%s\r\n", oper, *op_arg ? " " : "", op_arg);
|
||||
else
|
||||
e = ftp_cmd(conn, "%s %.*s", oper,
|
||||
e = ftp_cmd(conn, "%s %.*s\r\n", oper,
|
||||
filenamelen, filename);
|
||||
if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION)
|
||||
goto ouch;
|
||||
@ -940,11 +938,11 @@ ftp_authenticate(conn_t *conn, struct url *url, struct url *purl)
|
||||
if (user == NULL || *user == '\0')
|
||||
user = FTP_ANONYMOUS_USER;
|
||||
if (purl && url->port == fetch_default_port(url->scheme))
|
||||
e = ftp_cmd(conn, "USER %s@%s", user, url->host);
|
||||
e = ftp_cmd(conn, "USER %s@%s\r\n", user, url->host);
|
||||
else if (purl)
|
||||
e = ftp_cmd(conn, "USER %s@%s@%d", user, url->host, url->port);
|
||||
e = ftp_cmd(conn, "USER %s@%s@%d\r\n", user, url->host, url->port);
|
||||
else
|
||||
e = ftp_cmd(conn, "USER %s", user);
|
||||
e = ftp_cmd(conn, "USER %s\r\n", user);
|
||||
|
||||
/* did the server request a password? */
|
||||
if (e == FTP_NEED_PASSWORD) {
|
||||
@ -963,7 +961,7 @@ ftp_authenticate(conn_t *conn, struct url *url, struct url *purl)
|
||||
pbuf[sizeof(pbuf) - 1] = '\0';
|
||||
pwd = pbuf;
|
||||
}
|
||||
e = ftp_cmd(conn, "PASS %s", pwd);
|
||||
e = ftp_cmd(conn, "PASS %s\r\n", pwd);
|
||||
}
|
||||
|
||||
return (e);
|
||||
@ -996,10 +994,23 @@ ftp_connect(struct url *url, struct url *purl, const char *flags)
|
||||
/* check for proxy */
|
||||
if (purl) {
|
||||
/* XXX proxy authentication! */
|
||||
conn = fetch_connect(purl->host, purl->port, af, verbose);
|
||||
/* XXX connetion caching */
|
||||
if (!purl->port)
|
||||
purl->port = fetch_default_port(purl->scheme);
|
||||
|
||||
conn = fetch_connect(purl, af, verbose);
|
||||
} else {
|
||||
/* no proxy, go straight to target */
|
||||
conn = fetch_connect(url->host, url->port, af, verbose);
|
||||
if (!url->port)
|
||||
url->port = fetch_default_port(url->scheme);
|
||||
|
||||
while ((conn = fetch_cache_get(url, af)) != NULL) {
|
||||
e = ftp_cmd(conn, "NOOP\r\n");
|
||||
if (e == FTP_OK)
|
||||
return conn;
|
||||
fetch_close(conn);
|
||||
}
|
||||
conn = fetch_connect(url, af, verbose);
|
||||
purl = NULL;
|
||||
}
|
||||
|
||||
@ -1028,70 +1039,6 @@ fouch:
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disconnect from server
|
||||
*/
|
||||
static void
|
||||
ftp_disconnect(conn_t *conn)
|
||||
{
|
||||
(void)ftp_cmd(conn, "QUIT");
|
||||
if (conn == cached_connection && conn->ref == 1) {
|
||||
free(cached_host.doc);
|
||||
cached_host.doc = NULL;
|
||||
cached_connection = NULL;
|
||||
}
|
||||
fetch_close(conn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if we're already connected
|
||||
*/
|
||||
static int
|
||||
ftp_isconnected(struct url *url)
|
||||
{
|
||||
return (cached_connection
|
||||
&& (cached_connection->is_active == 0)
|
||||
&& (strcmp(url->host, cached_host.host) == 0)
|
||||
&& (strcmp(url->user, cached_host.user) == 0)
|
||||
&& (strcmp(url->pwd, cached_host.pwd) == 0)
|
||||
&& (url->port == cached_host.port));
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the cache, reconnect if no luck
|
||||
*/
|
||||
static conn_t *
|
||||
ftp_cached_connect(struct url *url, struct url *purl, const char *flags)
|
||||
{
|
||||
char *doc;
|
||||
conn_t *conn;
|
||||
int e;
|
||||
|
||||
/* set default port */
|
||||
if (!url->port)
|
||||
url->port = fetch_default_port(url->scheme);
|
||||
|
||||
/* try to use previously cached connection */
|
||||
if (ftp_isconnected(url)) {
|
||||
e = ftp_cmd(cached_connection, "NOOP");
|
||||
if (e == FTP_OK || e == FTP_SYNTAX_ERROR)
|
||||
return (fetch_ref(cached_connection));
|
||||
}
|
||||
|
||||
/* connect to server */
|
||||
if ((conn = ftp_connect(url, purl, flags)) == NULL)
|
||||
return (NULL);
|
||||
doc = strdup(url->doc);
|
||||
if (doc != NULL) {
|
||||
if (cached_connection && !cached_connection->is_active)
|
||||
ftp_disconnect(cached_connection);
|
||||
cached_connection = fetch_ref(conn);
|
||||
memcpy(&cached_host, url, sizeof(*url));
|
||||
cached_host.doc = doc;
|
||||
}
|
||||
return (conn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the proxy settings
|
||||
*/
|
||||
@ -1150,7 +1097,7 @@ ftp_request(struct url *url, const char *op, const char *op_arg,
|
||||
}
|
||||
|
||||
/* connect to server */
|
||||
conn = ftp_cached_connect(url, purl, flags);
|
||||
conn = ftp_connect(url, purl, flags);
|
||||
if (purl)
|
||||
fetchFreeURL(purl);
|
||||
if (conn == NULL)
|
||||
|
Reference in New Issue
Block a user