summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authornjl <njl@FreeBSD.org>2007-04-22 22:33:29 +0000
committernjl <njl@FreeBSD.org>2007-04-22 22:33:29 +0000
commita22d768e0f5024d4990559f51e5455f257b3570a (patch)
treef006c880f3cf9fdbcc8a2d241c97a04f1df75ce0 /lib
parent328ad8c39b7fe076c817f11235241bfd1a53e8ba (diff)
downloadFreeBSD-src-a22d768e0f5024d4990559f51e5455f257b3570a.zip
FreeBSD-src-a22d768e0f5024d4990559f51e5455f257b3570a.tar.gz
Add back the original behavior of changing the entire directory path at
once (CWD a/b/c vs. 3 CWDs). If an error occurs, we fall back to the default method of a single CWD per directory element. Since this is technically a violation of the basic FTP RFC, this behavior is under a compile-time option FTP_COMBINE_CWDS and is off by default. It should work with most Unix-based FTP daemons and can save latency. MFC after: 2 weeks
Diffstat (limited to 'lib')
-rw-r--r--lib/libfetch/fetch.312
-rw-r--r--lib/libfetch/ftp.c24
2 files changed, 34 insertions, 2 deletions
diff --git a/lib/libfetch/fetch.3 b/lib/libfetch/fetch.3
index 4c399b7..b145bb0 100644
--- a/lib/libfetch/fetch.3
+++ b/lib/libfetch/fetch.3
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 1, 1998
+.Dd April 22, 2007
.Dt FETCH 3
.Os
.Sh NAME
@@ -334,6 +334,16 @@ If no user name or password is given, the
.Nm fetch
library will attempt an anonymous login, with user name "anonymous"
and password "anonymous@<hostname>".
+.Pp
+By default,
+.Nm fetch
+changes directories one at a time for the best compatibility with a wide
+variety of servers.
+If it is compiled with the
+.Ql FTP_COMBINE_CWDS
+flag, it will first try a single change directory command for the entire
+path and fall back to the default scheme if an error occurred.
+This can save latency when used with a slow network link.
.Sh HTTP SCHEME
The
.Fn fetchXGetHTTP ,
diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c
index 92c51ed..3613c4c 100644
--- a/lib/libfetch/ftp.c
+++ b/lib/libfetch/ftp.c
@@ -267,6 +267,7 @@ _ftp_cwd(conn_t *conn, const char *file)
char pwd[PATH_MAX];
int e, i, len;
+ /* If no slashes in name, no need to change dirs. */
if ((end = strrchr(file, '/')) == NULL)
return (0);
if ((e = _ftp_cmd(conn, "PWD")) != FTP_WORKING_DIRECTORY ||
@@ -276,7 +277,8 @@ _ftp_cwd(conn_t *conn, const char *file)
}
for (;;) {
len = strlen(pwd);
- /* look for a common prefix */
+
+ /* Look for a common prefix between PWD and dir to fetch. */
for (i = 0; i <= len && i <= end - file; ++i)
if (pwd[i] != file[i])
break;
@@ -284,6 +286,7 @@ _ftp_cwd(conn_t *conn, const char *file)
DEBUG(fprintf(stderr, "have: [%.*s|%s]\n", i, pwd, pwd + i));
DEBUG(fprintf(stderr, "want: [%.*s|%s]\n", i, file, file + i));
#endif
+ /* Keep going up a dir until we have a matching prefix. */
if (pwd[i] == '\0' && (file[i - 1] == '/' || file[i] == '/'))
break;
if ((e = _ftp_cmd(conn, "CDUP")) != FTP_FILE_ACTION_OK ||
@@ -293,6 +296,23 @@ _ftp_cwd(conn_t *conn, const char *file)
return (-1);
}
}
+
+#ifdef FTP_COMBINE_CWDS
+ /* Skip leading slashes, even "////". */
+ for (beg = file + i; beg < end && *beg == '/'; ++beg, ++i)
+ /* nothing */ ;
+
+ /* If there is no trailing dir, we're already there. */
+ if (beg >= end)
+ 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);
+ if (e == FTP_FILE_ACTION_OK)
+ return (0);
+#endif /* FTP_COMBINE_CWDS */
+
+ /* That didn't work so go back to legacy behavior (multiple CWDs). */
for (beg = file + i; beg < end; beg = file + i + 1) {
while (*beg == '/')
++beg, ++i;
@@ -966,6 +986,8 @@ _ftp_connect(struct url *url, struct url *purl, const char *flags)
if ((e = _ftp_authenticate(conn, url, purl)) != FTP_LOGGED_IN)
goto fouch;
+ /* TODO: Request extended features supported, if any (RFC 3659). */
+
/* done */
return (conn);
OpenPOWER on IntegriCloud