Merge libfetch-2.30 from NetBSD's pkgsrc.

--HG--
extra : convert_revision : xtraeme%40gmail.com-20100124144753-ni487x8m7r05847b
This commit is contained in:
Juan RP
2010-01-24 15:47:53 +01:00
parent 489f6baaa6
commit 03e8fa53d9
5 changed files with 277 additions and 227 deletions

View File

@ -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)