Introduce fetchXGet*(), which combine the functionalities of fetchGet*() and

fetchStat*().  In most cases, either fetchGet*() or fetchXGet*() is a wrapper
around the other; in all cases, calling fetchGet*() is identical to calling
fetchXGet*() with the second argument set to NULL.
This commit is contained in:
Dag-Erling Smørgrav 2000-07-17 21:25:00 +00:00
parent c789727701
commit 1a5faa1061
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=63340
6 changed files with 236 additions and 113 deletions

View File

@ -31,22 +31,27 @@
.Nm fetchMakeURL ,
.Nm fetchParseURL ,
.Nm fetchFreeURL ,
.Nm fetchXGetURL ,
.Nm fetchGetURL ,
.Nm fetchPutURL ,
.Nm fetchStatURL ,
.Nm fetchListURL ,
.Nm fetchXGet ,
.Nm fetchGet ,
.Nm fetchPut ,
.Nm fetchStat ,
.Nm fetchList ,
.Nm fetchXGetFile ,
.Nm fetchGetFile ,
.Nm fetchPutFile ,
.Nm fetchStatFile ,
.Nm fetchListFile ,
.Nm fetchXGetHTTP ,
.Nm fetchGetHTTP ,
.Nm fetchPutHTTP ,
.Nm fetchStatHTTP ,
.Nm fetchListHTTP ,
.Nm fetchXGetFTP ,
.Nm fetchGetFTP ,
.Nm fetchPutFTP ,
.Nm fetchStatFTP ,
@ -65,6 +70,8 @@
.Ft void
.Fn fetchFreeURL "struct url *URL"
.Ft FILE *
.Fn fetchXGetURL "char *URL" "struct url_stat *us" "char *flags"
.Ft FILE *
.Fn fetchGetURL "char *URL" "char *flags"
.Ft FILE *
.Fn fetchPutURL "char *URL" "char *flags"
@ -73,6 +80,8 @@
.Ft struct url_ent *
.Fn fetchListURL "char *URL" "char *flags"
.Ft FILE *
.Fn fetchXGet "struct url *URL" "struct url_stat *us" "char *flags"
.Ft FILE *
.Fn fetchGet "struct url *URL" "char *flags"
.Ft FILE *
.Fn fetchPut "struct url *URL" "char *flags"
@ -81,6 +90,8 @@
.Ft struct url_ent *
.Fn fetchList "struct url *" "char *flags"
.Ft FILE *
.Fn fetchXGetFile "struct url *u" "struct url_stat *us" "char *flags"
.Ft FILE *
.Fn fetchGetFile "struct url *u" "char *flags"
.Ft FILE *
.Fn fetchPutFile "struct url *u" "char *flags"
@ -89,6 +100,8 @@
.Ft struct url_ent *
.Fn fetchListFile "struct url *" "char *flags"
.Ft FILE *
.Fn fetchXGetHTTP "struct url *u" "struct url_stat *us" "char *flags"
.Ft FILE *
.Fn fetchGetHTTP "struct url *u" "char *flags"
.Ft FILE *
.Fn fetchPutHTTP "struct url *u" "char *flags"
@ -97,6 +110,8 @@
.Ft struct url_ent *
.Fn fetchListHTTP "struct url *" "char *flags"
.Ft FILE *
.Fn fetchXGetFTP "struct url *u" "struct url_stat *us" "char *flags"
.Ft FILE *
.Fn fetchGetFTP "struct url *u" "char *flags"
.Ft FILE *
.Fn fetchPutFTP "struct url *u" "char *flags"
@ -154,7 +169,8 @@ or
should be freed using
.Fn fetchFreeURL .
.Pp
.Fn fetchGetURL
.Fn fetchXGetURL ,
.Fn fetchGetURL ,
and
.Fn fetchPutURL
constitute the recommended interface to the
@ -163,6 +179,13 @@ library.
They examine the URL passed to them to determine the transfer
method, and call the appropriate lower-level functions to perform the
actual transfer.
.Fn fetchXGetURL
also returns the remote document's metadata in the
.Fa url_stat
structure pointed to by the
.Fa us
argument.
.Pp
The
.Fa flags
argument is a string of characters which specify transfer options.
@ -219,11 +242,13 @@ The pointer returned by
should be freed using
.Fn free .
.Pp
.Fn fetchXGet ,
.Fn fetchGet ,
.Fn fetchPut
and
.Fn fetchStat
are similar to
.Fn fetchXGetURL ,
.Fn fetchGetURL ,
.Fn fetchPutURL
and
@ -234,6 +259,7 @@ a
rather than a string.
.Pp
All of the
.Fn fetchXGetXXX ,
.Fn fetchGetXXX
and
.Fn fetchPutXXX
@ -242,11 +268,14 @@ write data from or to the requested document, respectively.
Note that
although the implementation details of the individual access methods
vary, it can generally be assumed that a stream returned by one of the
.Fn fetchXGetXXX
or
.Fn fetchGetXXX
functions is read-only, and that a stream returned by one of the
.Fn fetchPutXXX
functions is write-only.
.Sh FILE SCHEME
.Fn fetchXGetFile ,
.Fn fetchGetFile
and
.Fn fetchPutFile
@ -254,8 +283,10 @@ provide access to documents which are files in a locally mounted file
system.
Only the <document> component of the URL is used.
.Pp
.Fn fetchXGetFile
and
.Fn fetchGetFile
does not accept any flags.
do not accept any flags.
.Pp
.Fn fetchPutFile
accepts the
@ -267,6 +298,7 @@ the stream returned by
will be appended to the previous contents of the file, instead of
replacing them.
.Sh FTP SCHEME
.Fn fetchXGetFTP ,
.Fn fetchGetFTP
and
.Fn fetchPutFTP
@ -286,6 +318,7 @@ port range (see
If the
.Fa d
(direct) flag is specified,
.Fn fetchXGetFTP ,
.Fn fetchGetFTP
and
.Fn fetchPutFTP
@ -297,6 +330,7 @@ library will attempt an anonymous login, with user name "ftp" and
password "ftp".
.Sh HTTP SCHEME
The
.Fn fetchXGetHTTP ,
.Fn fetchGetHTTP
and
.Fn fetchPutHTTP
@ -307,6 +341,7 @@ even a chance that they comply with RFC2068.
If the
.Fa d
(direct) flag is specified,
.Fn fetchXGetHTTP ,
.Fn fetchGetHTTP
and
.Fn fetchPutHTTP
@ -494,7 +529,8 @@ does not check that the result of an MDTM command is a valid date.
.Pp
The HTTP code needs a complete rewrite, or at least a serious cleanup.
.Pp
The man page is poorly written and produces badly formatted text.
The man page is incomplete, poorly written and produces badly
formatted text.
.Pp
The error reporting mechanism is unsatisfactory.
.Pp

View File

@ -67,28 +67,39 @@ static struct fetcherr _url_errlist[] = {
/*
* Select the appropriate protocol for the URL scheme, and return a
* read-only stream connected to the document referenced by the URL.
* Also fill out the struct url_stat.
*/
FILE *
fetchGet(struct url *URL, char *flags)
fetchXGet(struct url *URL, struct url_stat *us, char *flags)
{
int direct;
direct = (flags && strchr(flags, 'd'));
if (strcasecmp(URL->scheme, "file") == 0)
return fetchGetFile(URL, flags);
return fetchXGetFile(URL, us, flags);
else if (strcasecmp(URL->scheme, "http") == 0)
return fetchGetHTTP(URL, flags);
return fetchXGetHTTP(URL, us, flags);
else if (strcasecmp(URL->scheme, "ftp") == 0) {
if (!direct &&
getenv("FTP_PROXY") == NULL && getenv("HTTP_PROXY") != NULL)
return fetchGetHTTP(URL, flags);
return fetchGetFTP(URL, flags);
return fetchXGetHTTP(URL, us, flags);
return fetchXGetFTP(URL, us, flags);
} else {
_url_seterr(URL_BAD_SCHEME);
return NULL;
}
}
/*
* Select the appropriate protocol for the URL scheme, and return a
* read-only stream connected to the document referenced by the URL.
*/
FILE *
fetchGet(struct url *URL, char *flags)
{
return fetchXGet(URL, NULL, flags);
}
/*
* Select the appropriate protocol for the URL scheme, and return a
* write-only stream connected to the document referenced by the URL.
@ -165,10 +176,10 @@ fetchList(struct url *URL, char *flags)
}
/*
* Attempt to parse the given URL; if successful, call fetchGet().
* Attempt to parse the given URL; if successful, call fetchXGet().
*/
FILE *
fetchGetURL(char *URL, char *flags)
fetchXGetURL(char *URL, struct url_stat *us, char *flags)
{
struct url *u;
FILE *f;
@ -176,12 +187,20 @@ fetchGetURL(char *URL, char *flags)
if ((u = fetchParseURL(URL)) == NULL)
return NULL;
f = fetchGet(u, flags);
f = fetchXGet(u, us, flags);
fetchFreeURL(u);
return f;
}
/*
* Attempt to parse the given URL; if successful, call fetchGet().
*/
FILE *
fetchGetURL(char *URL, char *flags)
{
return fetchXGetURL(URL, NULL, flags);
}
/*
* Attempt to parse the given URL; if successful, call fetchPut().

View File

@ -81,28 +81,33 @@ struct url_ent {
#define FETCH_VERBOSE 19
/* FILE-specific functions */
FILE *fetchXGetFile(struct url *, struct url_stat *, char *);
FILE *fetchGetFile(struct url *, char *);
FILE *fetchPutFile(struct url *, char *);
int fetchStatFile(struct url *, struct url_stat *, char *);
struct url_ent *fetchListFile(struct url *, char *);
/* HTTP-specific functions */
FILE *fetchXGetHTTP(struct url *, struct url_stat *, char *);
FILE *fetchGetHTTP(struct url *, char *);
FILE *fetchPutHTTP(struct url *, char *);
int fetchStatHTTP(struct url *, struct url_stat *, char *);
struct url_ent *fetchListHTTP(struct url *, char *);
/* FTP-specific functions */
FILE *fetchXGetFTP(struct url *, struct url_stat *, char *);
FILE *fetchGetFTP(struct url *, char *);
FILE *fetchPutFTP(struct url *, char *);
int fetchStatFTP(struct url *, struct url_stat *, char *);
struct url_ent *fetchListFTP(struct url *, char *);
/* Generic functions */
FILE *fetchXGetURL(char *, struct url_stat *, char *);
FILE *fetchGetURL(char *, char *);
FILE *fetchPutURL(char *, char *);
int fetchStatURL(char *, struct url_stat *, char *);
struct url_ent *fetchListURL(char *, char *);
FILE *fetchXGet(struct url *, struct url_stat *, char *);
FILE *fetchGet(struct url *, char *);
FILE *fetchPut(struct url *, char *);
int fetchStat(struct url *, struct url_stat *, char *);

View File

@ -39,10 +39,13 @@
#include "common.h"
FILE *
fetchGetFile(struct url *u, char *flags)
fetchXGetFile(struct url *u, struct url_stat *us, char *flags)
{
FILE *f;
if (us && fetchStatFile(u, us, flags) == -1)
return NULL;
f = fopen(u->doc, "r");
if (f == NULL)
@ -56,6 +59,12 @@ fetchGetFile(struct url *u, char *flags)
return f;
}
FILE *
fetchGetFile(struct url *u, char *flags)
{
return fetchXGetFile(u, NULL, flags);
}
FILE *
fetchPutFile(struct url *u, char *flags)
{

View File

@ -193,6 +193,111 @@ _ftp_cmd(int cd, char *fmt, ...)
return _ftp_chkerr(cd);
}
/*
* Return a pointer to the filename part of a path
*/
static char *
_ftp_filename(char *file)
{
char *s;
if ((s = strrchr(file, '/')) == NULL)
return file;
else
return s + 1;
}
/*
* Change working directory to the directory that contains the
* specified file.
*/
static int
_ftp_cwd(int cd, char *file)
{
char *s;
int e;
if ((s = strrchr(file, '/')) == NULL) {
e = _ftp_cmd(cd, "CWD /");
} else {
e = _ftp_cmd(cd, "CWD %.*s", s - file, file);
}
if (e != FTP_FILE_ACTION_OK) {
_ftp_seterr(e);
return -1;
}
return 0;
}
/*
* Request and parse file stats
*/
static int
_ftp_stat(int cd, char *file, struct url_stat *us)
{
char *ln, *s;
struct tm tm;
time_t t;
int e;
if ((s = strrchr(file, '/')) == NULL)
s = file;
else
++s;
if ((e = _ftp_cmd(cd, "SIZE %s", s)) != FTP_FILE_STATUS) {
_ftp_seterr(e);
return -1;
}
for (ln = last_reply + 4; *ln && isspace(*ln); ln++)
/* nothing */ ;
for (us->size = 0; *ln && isdigit(*ln); ln++)
us->size = us->size * 10 + *ln - '0';
if (*ln && !isspace(*ln)) {
_ftp_seterr(FTP_PROTOCOL_ERROR);
return -1;
}
DEBUG(fprintf(stderr, "size: [\033[1m%lld\033[m]\n", us->size));
if ((e = _ftp_cmd(cd, "MDTM %s", s)) != FTP_FILE_STATUS) {
_ftp_seterr(e);
return -1;
}
for (ln = last_reply + 4; *ln && isspace(*ln); ln++)
/* nothing */ ;
switch (strspn(ln, "0123456789")) {
case 14:
break;
case 15:
ln++;
ln[0] = '2';
ln[1] = '0';
break;
default:
_ftp_seterr(FTP_PROTOCOL_ERROR);
return -1;
}
if (sscanf(ln, "%04d%02d%02d%02d%02d%02d",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
_ftp_seterr(FTP_PROTOCOL_ERROR);
return -1;
}
tm.tm_mon--;
tm.tm_year -= 1900;
tm.tm_isdst = -1;
t = timegm(&tm);
if (t == (time_t)-1)
t = time(NULL);
us->mtime = t;
us->atime = t;
DEBUG(fprintf(stderr, "last modified: [\033[1m%04d-%02d-%02d "
"%02d:%02d:%02d\033[m]\n",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec));
return 0;
}
/*
* Transfer file
*/
@ -218,30 +323,6 @@ _ftp_transfer(int cd, char *oper, char *file,
if (!pasv && (s = getenv("FTP_PASSIVE_MODE")) != NULL)
pasv = (strncasecmp(s, "no", 2) != 0);
/* change directory */
if (((s = strrchr(file, '/')) != NULL) && (s != file)) {
*s = 0;
if (verbose)
_fetch_info("changing directory to %s", file);
if ((e = _ftp_cmd(cd, "CWD %s", file)) != FTP_FILE_ACTION_OK) {
*s = '/';
if (e != -1)
_ftp_seterr(e);
return NULL;
}
*s++ = '/';
} else {
if (verbose)
_fetch_info("changing directory to /");
if ((e = _ftp_cmd(cd, "CWD /")) != FTP_FILE_ACTION_OK) {
if (e != -1)
_ftp_seterr(e);
return NULL;
}
}
/* s now points to file name */
/* find our own address, bind, and listen */
l = sizeof sin;
if (getsockname(cd, (struct sockaddr *)&sin, &l) == -1)
@ -366,7 +447,7 @@ _ftp_transfer(int cd, char *oper, char *file,
/* make the server initiate the transfer */
if (verbose)
_fetch_info("initiating transfer");
e = _ftp_cmd(cd, "%s %s", oper, s);
e = _ftp_cmd(cd, "%s %s", oper, _ftp_filename(file));
if (e != FTP_OPEN_DATA_CONNECTION)
goto ouch;
@ -456,7 +537,7 @@ _ftp_transfer(int cd, char *oper, char *file,
/* make the server initiate the transfer */
if (verbose)
_fetch_info("initiating transfer");
e = _ftp_cmd(cd, "%s %s", oper, s);
e = _ftp_cmd(cd, "%s %s", oper, _ftp_filename(file));
if (e != FTP_OPEN_DATA_CONNECTION)
goto ouch;
@ -675,10 +756,10 @@ _ftp_cached_connect(struct url *url, char *flags)
}
/*
* Get file
* Get and stat file
*/
FILE *
fetchGetFTP(struct url *url, char *flags)
fetchXGetFTP(struct url *url, struct url_stat *us, char *flags)
{
int cd;
@ -686,10 +767,27 @@ fetchGetFTP(struct url *url, char *flags)
if ((cd = _ftp_cached_connect(url, flags)) == NULL)
return NULL;
/* change directory */
if (_ftp_cwd(cd, url->doc) == -1)
return NULL;
/* stat file */
if (us && _ftp_stat(cd, url->doc, us) == -1)
return NULL;
/* initiate the transfer */
return _ftp_transfer(cd, "RETR", url->doc, "r", url->offset, flags);
}
/*
* Get file
*/
FILE *
fetchGetFTP(struct url *url, char *flags)
{
return fetchXGetFTP(url, NULL, flags);
}
/*
* Put file
*/
@ -702,6 +800,10 @@ fetchPutFTP(struct url *url, char *flags)
if ((cd = _ftp_cached_connect(url, flags)) == NULL)
return NULL;
/* change directory */
if (_ftp_cwd(cd, url->doc) == -1)
return NULL;
/* initiate the transfer */
return _ftp_transfer(cd, (flags && strchr(flags, 'a')) ? "APPE" : "STOR",
url->doc, "w", url->offset, flags);
@ -713,10 +815,7 @@ fetchPutFTP(struct url *url, char *flags)
int
fetchStatFTP(struct url *url, struct url_stat *us, char *flags)
{
char *ln, *s;
struct tm tm;
time_t t;
int e, cd;
int cd;
us->size = -1;
us->atime = us->mtime = 0;
@ -726,70 +825,11 @@ fetchStatFTP(struct url *url, struct url_stat *us, char *flags)
return -1;
/* change directory */
if (((s = strrchr(url->doc, '/')) != NULL) && (s != url->doc)) {
*s = 0;
if ((e = _ftp_cmd(cd, "CWD %s", url->doc)) != FTP_FILE_ACTION_OK) {
*s = '/';
goto ouch;
}
*s++ = '/';
} else {
if ((e = _ftp_cmd(cd, "CWD /")) != FTP_FILE_ACTION_OK)
goto ouch;
}
/* s now points to file name */
if (_ftp_cmd(cd, "SIZE %s", s) != FTP_FILE_STATUS)
goto ouch;
for (ln = last_reply + 4; *ln && isspace(*ln); ln++)
/* nothing */ ;
for (us->size = 0; *ln && isdigit(*ln); ln++)
us->size = us->size * 10 + *ln - '0';
if (*ln && !isspace(*ln)) {
_ftp_seterr(FTP_PROTOCOL_ERROR);
if (_ftp_cwd(cd, url->doc) == -1)
return -1;
}
DEBUG(fprintf(stderr, "size: [\033[1m%lld\033[m]\n", us->size));
if ((e = _ftp_cmd(cd, "MDTM %s", s)) != FTP_FILE_STATUS)
goto ouch;
for (ln = last_reply + 4; *ln && isspace(*ln); ln++)
/* nothing */ ;
e = FTP_PROTOCOL_ERROR;
switch (strspn(ln, "0123456789")) {
case 14:
break;
case 15:
ln++;
ln[0] = '2';
ln[1] = '0';
break;
default:
goto ouch;
}
if (sscanf(ln, "%04d%02d%02d%02d%02d%02d",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday,
&tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6)
goto ouch;
tm.tm_mon--;
tm.tm_year -= 1900;
tm.tm_isdst = -1;
t = timegm(&tm);
if (t == (time_t)-1)
t = time(NULL);
us->mtime = t;
us->atime = t;
DEBUG(fprintf(stderr, "last modified: [\033[1m%04d-%02d-%02d "
"%02d:%02d:%02d\033[m]\n",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec));
return 0;
ouch:
if (e != -1)
_ftp_seterr(e);
return -1;
/* stat file */
return _ftp_stat(cd, url->doc, us);
}
/*

View File

@ -772,8 +772,10 @@ _http_request(struct url *URL, char *op, struct url_stat *us, char *flags)
for (url = URL, i = 0; i < n; ++i) {
new = NULL;
us->size = -1;
us->atime = us->mtime = 0;
if (us) {
us->size = -1;
us->atime = us->mtime = 0;
}
chunked = 0;
need_auth = 0;
offset = 0;
@ -883,13 +885,15 @@ _http_request(struct url *URL, char *op, struct url_stat *us, char *flags)
_http_seterr(HTTP_PROTOCOL_ERROR);
goto ouch;
case hdr_content_length:
us->size = _http_parse_length(p);
if (us)
us->size = _http_parse_length(p);
break;
case hdr_content_range:
offset = _http_parse_range(p);
break;
case hdr_last_modified:
us->atime = us->mtime = _http_parse_mtime(p);
if (us)
us->atime = us->mtime = _http_parse_mtime(p);
break;
case hdr_location:
if (!HTTP_REDIRECT(code))
@ -977,17 +981,27 @@ _http_request(struct url *URL, char *op, struct url_stat *us, char *flags)
* Entry points
*/
/*
* Retrieve and stat a file by HTTP
*/
FILE *
fetchXGetHTTP(struct url *URL, struct url_stat *us, char *flags)
{
return _http_request(URL, "GET", us, flags);
}
/*
* Retrieve a file by HTTP
*/
FILE *
fetchGetHTTP(struct url *URL, char *flags)
{
struct url_stat us;
return _http_request(URL, "GET", &us, flags);
return fetchXGetHTTP(URL, NULL, flags);
}
/*
* Store a file by HTTP
*/
FILE *
fetchPutHTTP(struct url *URL, char *flags)
{