From 93ce759c73e21f7ac6642b79a8e6146522b452aa Mon Sep 17 00:00:00 2001 From: des Date: Fri, 6 Nov 1998 22:14:08 +0000 Subject: Second of a series of cleanups to libfetch. This commit introduces the following features: a) the fetchStat*() functions, which return meta-information for a document, such as size, modification time, etc. b) the use of the com_err(3) facilities to report errors. It also fixes a bunch of style bugs and a few logic bugs and somewhat improves the man page. Changed files, in alphabetical order: Makefile: Don't generate macros in {ftp,http}err.c. Generate category fields for the error message lists. Compile the error table. Install fetch_err.h along with fetch.h. common.c: Remove the _netdb_errstring() macro, and add FETCH_ERR_NETDB to the error code in the _netdb_seterr() macro. Add categories to the _netdb_errlist table. Report errors through the Common Error library. common.h: Add the DEBUG macros. Add prototype for fetchConnect(). Remove the prototype for _fetch_errstring(), which is local to common.c Add a categroy field to struct fetcherr, and define constants for error categories. Define macros for _{url,netdb,ftp,http}_seterr(). errors.et: (new file) List error categories. fetch.3: Document the fetchStat*() functions. Move the "unimplemented functionality" comments from NOTES to BUGS. Document that applications which use libfetch must also use libcom_err, and list existing error codes. Undocument fetchLastErr{Code,String}. Remove the (empty) DIAGNOSTICS section. Mention Eugene Skepner in the AUTHORS section. fetch.c: Move the DEBUG macros to common.c Add fetchStat() and fetchStatURL(). Generate error messages for URL parser errors, and fix a minor bug in the parser. Use 'struct url' instead of 'url_t'. Remove fetchLastErr{Code,String}. fetch.h: Use 'struct url' instead of 'url_t', and remove the typedef. Define struct url_stat (used by fetchStat()). Add prototypes for fetchStat*(). Remove the declarations for fetchLastErr{Code,String}. Include fetch_err.h. fetch_err.et: (new file) Error table for libfetch. file.c: Add fetchStatFile(). Use 'struct url' instead of 'url_t'. ftp.c: Add fetchStatFTP(). Use 'struct url' instead of 'url_t'. Don't use fetchLastErrCode. ftp.errors: Add categories to all error messages. http.c: Add fetchStatHTTP(). Use 'struct url' instead of 'url_t'. Don't use fetchLastErr{Code,Text}. http.errors: Add categories to all error messages. Prompted by: jkh and Eugene Skepner Numerous sugestions from: Garett Wollman and Eugene Skepner --- lib/libfetch/Makefile | 37 +++++------ lib/libfetch/common.c | 107 ++++++++++++++++++++++++------ lib/libfetch/common.h | 20 ++++-- lib/libfetch/fetch.3 | 162 +++++++++++++++++++++++++++++++++++----------- lib/libfetch/fetch.c | 112 +++++++++++++++++++++++++------- lib/libfetch/fetch.h | 58 +++++++++-------- lib/libfetch/fetch_err.et | 49 ++++++++++++++ lib/libfetch/file.c | 43 ++++++++++-- lib/libfetch/ftp.c | 33 ++++++---- lib/libfetch/ftp.errors | 80 +++++++++++------------ lib/libfetch/http.c | 23 +++++-- lib/libfetch/http.errors | 76 +++++++++++----------- 12 files changed, 569 insertions(+), 231 deletions(-) create mode 100644 lib/libfetch/fetch_err.et (limited to 'lib/libfetch') diff --git a/lib/libfetch/Makefile b/lib/libfetch/Makefile index ca48d06..14fc44c 100644 --- a/lib/libfetch/Makefile +++ b/lib/libfetch/Makefile @@ -1,12 +1,12 @@ -# $Id: Makefile,v 1.5 1998/08/17 20:39:09 bde Exp $ +# $Id: Makefile,v 1.6 1998/11/05 19:48:16 des Exp $ LIB= fetch CFLAGS+= -I. -Wall -pedantic .if !defined(DEBUG) CFLAGS+= -DNDEBUG .endif -SRCS= fetch.c common.c ftp.c http.c file.c -DPSRCS= ftperr.c httperr.c +SRCS= fetch.c common.c ftp.c http.c file.c fetch_err.c +DPSRCS= ftperr.inc httperr.inc fetch_err.c fetch_err.h MAN3= fetch.3 CLEANFILES= ${DPSRCS} @@ -15,36 +15,37 @@ SHLIB_MINOR= 0 beforedepend: ${DPSRCS} -beforeinstall: +beforeinstall: fetch.h fetch_err.h ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/fetch.h \ ${DESTDIR}/usr/include + ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/fetch_err.h \ + ${DESTDIR}/usr/include -ftperr.c: ftp.errors - @echo "static struct fetcherr _ftp_errlist[] = {" \ >> ${.TARGET} +ftperr.inc: ftp.errors + @echo "static struct fetcherr _ftp_errlist[] = {" > ${.TARGET} @cat ${.ALLSRC} \ | grep -v ^# \ | sort \ - | while read NUM STRING; do \ - echo " { $${NUM}, \"$${STRING}\" },"; \ + | while read NUM CAT STRING; do \ + echo " { $${NUM}, FETCH_$${CAT}, \"$${STRING}\" },"; \ done >> ${.TARGET} - @echo " { -1, \"Unknown FTP error\" }" >> ${.TARGET} + @echo " { -1, FETCH_UNKNOWN, \"Unknown FTP error\" }" >> ${.TARGET} @echo "};" >> ${.TARGET} - @echo "#define _ftp_errstring(n) _fetch_errstring(_ftp_errlist, n)" >> ${.TARGET} - @echo "#define _ftp_seterr(n) _fetch_seterr(_ftp_errlist, n)" >> ${.TARGET} -httperr.c: http.errors - @echo "static struct fetcherr _http_errlist[] = {" \ >> ${.TARGET} +httperr.inc: http.errors + @echo "static struct fetcherr _http_errlist[] = {" > ${.TARGET} @cat ${.ALLSRC} \ | grep -v ^# \ | sort \ - | while read NUM STRING; do \ - echo " { $${NUM}, \"$${STRING}\" },"; \ + | while read NUM CAT STRING; do \ + echo " { $${NUM}, FETCH_$${CAT}, \"$${STRING}\" },"; \ done >> ${.TARGET} - @echo " { -1, \"Unknown HTTP error\" }" >> ${.TARGET} + @echo " { -1, FETCH_UNKNOWN, \"Unknown FTP error\" }" >> ${.TARGET} @echo "};" >> ${.TARGET} - @echo "#define _http_errstring(n) _fetch_errstring(_http_errlist, n)" >> ${.TARGET} - @echo "#define _http_seterr(n) _fetch_seterr(_http_errlist, n)" >> ${.TARGET} + +fetch_err.c fetch_err.h: fetch_err.et + compile_et ${.ALLSRC} .include diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c index be0da67..c42f2db 100644 --- a/lib/libfetch/common.c +++ b/lib/libfetch/common.c @@ -25,13 +25,14 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id$ + * $Id: common.c,v 1.1 1998/11/05 19:48:16 des Exp $ */ #include #include #include +#include #include #include #include @@ -40,34 +41,45 @@ #include "fetch.h" #include "common.h" + /*** Local data **************************************************************/ /* * Error messages for resolver errors */ static struct fetcherr _netdb_errlist[] = { - { HOST_NOT_FOUND, "Host not found" }, - { TRY_AGAIN, "Transient resolver failure" }, - { NO_RECOVERY, "Non-recoverable resolver failure" }, - { NO_DATA, "No address record" }, - { -1, "Unknown resolver error" } + { HOST_NOT_FOUND, FETCH_RESOLV, "Host not found" }, + { TRY_AGAIN, FETCH_RESOLV, "Transient resolver failure" }, + { NO_RECOVERY, FETCH_RESOLV, "Non-recoverable resolver failure" }, + { NO_DATA, FETCH_RESOLV, "No address record" }, + { -1, FETCH_UNKNOWN, "Unknown resolver error" } }; -#define _netdb_errstring(n) _fetch_errstring(_netdb_errlist, n) -#define _netdb_seterr(n) _fetch_seterr(_netdb_errlist, n) +static int com_err_initialized; /*** Error-reporting functions ***********************************************/ /* + * Initialize the common error library + */ +static void +_fetch_init_com_err(void) +{ + initialize_ftch_error_table(); + com_err_initialized = 1; +} + +/* * Map error code to string */ -const char * -_fetch_errstring(struct fetcherr *p, int e) +static int +_fetch_finderr(struct fetcherr *p, int e) { - while ((p->num != -1) && (p->num != e)) - p++; - - return p->string; + int i; + for (i = 0; p[i].num != -1; i++) + if (p[i].num == e) + break; + return i; } /* @@ -76,8 +88,13 @@ _fetch_errstring(struct fetcherr *p, int e) void _fetch_seterr(struct fetcherr *p, int e) { - fetchLastErrCode = e; - fetchLastErrText = _fetch_errstring(p, e); + int n; + + if (!com_err_initialized) + _fetch_init_com_err(); + + n = _fetch_finderr(p, e); + com_err("libfetch", p[n].cat, "(%d %s)", e, p[n].string); } /* @@ -86,8 +103,62 @@ _fetch_seterr(struct fetcherr *p, int e) void _fetch_syserr(void) { - fetchLastErrCode = errno; - fetchLastErrText = strerror(errno); + int cat; + + if (!com_err_initialized) + _fetch_init_com_err(); + + switch (errno) { + case 0: + cat = FETCH_OK; + break; + case EPERM: + case EACCES: + case EROFS: + case EAUTH: + case ENEEDAUTH: + cat = FETCH_AUTH; + break; + case ENOENT: + case EISDIR: /* XXX */ + cat = FETCH_UNAVAIL; + break; + case ENOMEM: + cat = FETCH_MEMORY; + break; + case EBUSY: + case EAGAIN: + cat = FETCH_TEMP; + break; + case EEXIST: + cat = FETCH_EXISTS; + break; + case ENOSPC: + cat = FETCH_FULL; + break; + case EADDRINUSE: + case EADDRNOTAVAIL: + case ENETDOWN: + case ENETUNREACH: + case ENETRESET: + case EHOSTUNREACH: + cat = FETCH_NETWORK; + break; + case ECONNABORTED: + case ECONNRESET: + cat = FETCH_ABORT; + break; + case ETIMEDOUT: + cat = FETCH_TIMEOUT; + break; + case ECONNREFUSED: + case EHOSTDOWN: + cat = FETCH_DOWN; + break; + default: + cat = FETCH_UNKNOWN; + } + com_err("libfetch", cat, "(%02d %s)", errno, strerror(errno)); } diff --git a/lib/libfetch/common.h b/lib/libfetch/common.h index f031b91..dc2a42e 100644 --- a/lib/libfetch/common.h +++ b/lib/libfetch/common.h @@ -25,20 +25,32 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id$ + * $Id: common.h,v 1.1 1998/11/05 19:48:16 des Exp $ */ #ifndef _COMMON_H_INCLUDED #define _COMMON_H_INCLUDED /* Structure used for error message lists */ +#define ERRCAT_ struct fetcherr { - const int num; - const char *string; + const int num, cat; + const char *string; }; -const char *_fetch_errstring(struct fetcherr *, int); void _fetch_seterr(struct fetcherr *, int); void _fetch_syserr(void); +int fetchConnect(char *, int); +#define _ftp_seterr(n) _fetch_seterr(_ftp_errlist, n) +#define _http_seterr(n) _fetch_seterr(_http_errlist, n) +#define _netdb_seterr(n) _fetch_seterr(_netdb_errlist, n) +#define _url_seterr(n) _fetch_seterr(_url_errlist, n) + +#ifndef NDEBUG +#define DEBUG(x) do x; while (0) +#else +#define DEBUG(x) do { } while (0) +#endif + #endif diff --git a/lib/libfetch/fetch.3 b/lib/libfetch/fetch.3 index 2b4c63a..f384fd6 100644 --- a/lib/libfetch/fetch.3 +++ b/lib/libfetch/fetch.3 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $Id: fetch.3,v 1.2 1998/09/26 20:42:44 des Exp $ +.\" $Id: fetch.3,v 1.3 1998/11/05 19:48:16 des Exp $ .\" .Dd July 1, 1998 .Dt FETCH 3 @@ -30,15 +30,20 @@ .Sh NAME .Nm fetchGetURL , .Nm fetchPutURL , +.Nm fetchStatURL , .Nm fetchParseURL , .Nm fetchGet , .Nm fetchPut , +.Nm fetchStat , .Nm fetchGetFile , .Nm fetchPutFile , +.Nm fetchStatFile , .Nm fetchGetHTTP , .Nm fetchPutHTTP , +.Nm fetchStatHTTP , .Nm fetchGetFTP , .Nm fetchPutFTP +.Nm fetchStatFTP .Nd file transfer library .Sh SYNOPSIS .Fd #include @@ -46,27 +51,36 @@ .Fn fetchGetURL "char *URL" "char *flags" .Ft FILE * .Fn fetchPutURL "char *URL" "char *flags" -.Ft url_t * +.Ft int +.Fn fetchStatURL "char *URL" "struct url_stat *us" "char *flags" +.Ft struct url * .Fn fetchParseURL "char *URL" "char *flags" .Ft FILE * -.Fn fetchGet "url_t *URL" "char *flags" +.Fn fetchGet "struct url *URL" "char *flags" .Ft FILE * -.Fn fetchPut "url_t *URL" "char *flags" +.Fn fetchPut "struct url *URL" "char *flags" +.Ft int +.Fn fetchStat "struct url *URL" "struct url_stat *us" "char *flags" .Ft FILE * -.Fn fetchGetFile "url_t *u" "char *flags" +.Fn fetchGetFile "struct url *u" "char *flags" .Ft FILE * -.Fn fetchPutFile "url_t *u" "char *flags" +.Fn fetchPutFile "struct url *u" "char *flags" +.Ft int +.Fn fetchStatFile "struct url *URL" "struct url_stat *us" "char *flags" .Ft FILE * -.Fn fetchGetHTTP "url_t *u" "char *flags" +.Fn fetchGetHTTP "struct url *u" "char *flags" .Ft FILE * -.Fn fetchPutHTTP "url_t *u" "char *flags" +.Fn fetchPutHTTP "struct url *u" "char *flags" +.Ft int +.Fn fetchStatHTTP "struct url *URL" "struct url_stat *us" "char *flags" .Ft FILE * -.Fn fetchGetFTP "url_t *u" "char *flags" +.Fn fetchGetFTP "struct url *u" "char *flags" .Ft FILE * -.Fn fetchPutFTP "url_t *u" "char *flags" -.Vt extern int fetchLastErrCode; -.Vt extern const char *fetchLastErrText; +.Fn fetchPutFTP "struct url *u" "char *flags" +.Ft int +.Fn fetchStatFTP "struct url *URL" "struct url_stat *us" "char *flags" .Sh DESCRIPTION +.Pp These functions implement a high-level library for retrieving and uploading files using Uniform Resource Locators (URLs). .Pp @@ -83,6 +97,19 @@ argument is a string of characters which specify transfer options. The meaning of the individual flags is scheme-dependent, and is detailed in the appropriate section below. .Pp +.Fn fetchStatURL +attempts to obtain the requested document's metadata and fill in the +structure pointed to by it's second argument. The +.Fa url_stat +structure is defined as follows in +.Aq Pa fetch.h : +.Bd -literal +struct url_stat { + off_t size; + time_t time; +}; +.Ed +.Pp .Fn fetchParseURL takes a URL in the form of a null-terminated string and splits it into its components function according to the Common Internet Scheme Syntax @@ -101,17 +128,19 @@ The pointer returned by should be freed using .Fn free . .Pp -.Fn fetchGet -and +.Fn fetchGet , .Fn fetchPut +and +.Fn fetchStat are similar to -.Fn fetchGetURL +.Fn fetchGetURL , +.Fn fetchPutURL and -.Fn fetchPutURL , +.Fn fetchStatURL , except that they expect a pre-parsed URL in the form of a pointer to -an -.Fa url_t -structure rather than a string. +a +.Fa struct url +rather than a string. .Pp All of the .Fn fetchGetXXX @@ -175,19 +204,66 @@ is currently unimplemented. .Sh RETURN VALUES .Fn fetchParseURL returns a pointer to a -.Fa url_t -structure containing the individual components of the URL. If it is +.Fa struct url +containing the individual components of the URL. If it is unable to allocate memory, or the URL is syntactically incorrect, .Fn fetchParseURL returns a NULL pointer. .Pp +The +.Fn fetchStat +functions return 0 on success and -1 on failure. +.Pp All other functions return a stream pointer which may be used to -access the requested document, or NULL if an error occurred. In the -latter case, the variables -.Va fetchLastErrCode -and -.Va fetchLastErrText -are set to appropriately descriptive values. +access the requested document, or NULL if an error occurred. +.Pp +.Nm Libfetch +uses the Common Error Library +.Nm ( libcom_err ) +to report errors. The error code passed to +.Fn com_err +is one of: +.Bl -tag -width Er +.It Bq Er FETCH_ABORT +Operation aborted +.It Bq Er FETCH_AUTH +Authentication failed +.It Bq Er FETCH_DOWN +Service unavailable +.It Bq Er FETCH_EXISTS +File exists +.It Bq Er FETCH_FULL +File system full +.It Bq Er FETCH_INFO +Informational response +.It Bq Er FETCH_MEMORY +Insufficient memory +.It Bq Er FETCH_MOVED +File has moved +.It Bq Er FETCH_NETWORK +Network error +.It Bq Er FETCH_OK +No error +.It Bq Er FETCH_PROTO +Protocol error +.It Bq Er FETCH_RESOLV +Resolver error +.It Bq Er FETCH_SERVER +Server error +.It Bq Er FETCH_TEMP +Temporary error +.It Bq Er FETCH_TIMEOUT +Operation timed out +.It Bq Er FETCH_UNAVAIL +File is not available +.It Bq Er FETCH_UNKNOWN +Unknown error +.It Bq Er FETCH_URL +Invalid URL +.El +.Pp +The accompanying error message includes a protocol-specific error code +and message, e.g. "File is not available (404 Not Found)" .Sh ENVIRONMENT The FTP and HTTP related functions use the .Ev HTTP_PROXY @@ -196,6 +272,7 @@ and environment variables, respectively, as the address of a proxy server to use for transferring files. .Sh SEE ALSO +.Xr com_err 3 , .Xr fetch 1 , .Xr ftpio 3 .Rs @@ -216,13 +293,14 @@ to use for transferring files. .%B File Transfer Protocol .%O RFC959 .Re -.Sh DIAGNOSTICS -Add later. .Sh NOTES -Some parts of the library are not yet implemented. The most notable -examples of this are -.Fn fetchPutHTTP -and proxy support for the FTP access method. +The +.Nm fetch +library uses the Common Error library, and applications which link +with +.Nm libfetch +must therefore also link with +.Nm libcom_err . .Sh HISTORY The .Nm fetch @@ -234,18 +312,26 @@ The library was mostly written by .An Dag-Erling Coïdan Smørgrav Aq des@FreeBSD.org with numerous suggestions from -.An Jordan K. Hubbard Aq jkh@FreeBSD.org +.An Jordan K. Hubbard Aq jkh@FreeBSD.org , +.An Eugene Skepner Aq eu@qub.com and other FreeBSD developers. -It incorporates the older +It replaces the older .Nm ftpio -library, which was originally written by -.Nm Poul-Henning Kamp Aq pkh@FreeBSD.org -and later turned inside out by +library written by +.An Poul-Henning Kamp Aq pkh@FreeBSD.org +and .An Jordan K. Hubbard Aq jkh@FreeBSD.org . .Pp This manual page was written by .An Dag-Erling Coïdan Smørgrav Aq des@FreeBSD.org .Sh BUGS +Some parts of the library are not yet implemented. The most notable +examples of this are +.Fn fetchPutHTTP , +.Fn fetchStatFTP , +.Fn fetchStatHTTP +and FTP proxy support. +.Pp There's no way to select a proxy at run-time other than setting the .Ev HTTP_PROXY or diff --git a/lib/libfetch/fetch.c b/lib/libfetch/fetch.c index 226b628..20cf675 100644 --- a/lib/libfetch/fetch.c +++ b/lib/libfetch/fetch.c @@ -25,10 +25,11 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: fetch.c,v 1.4 1998/08/17 09:30:19 des Exp $ + * $Id: fetch.c,v 1.5 1998/11/05 19:48:17 des Exp $ */ #include +#include #include #include @@ -36,22 +37,33 @@ #include #include "fetch.h" +#include "common.h" -#ifndef NDEBUG -#define DEBUG(x) do x; while (0) -#else -#define DEBUG(x) do { } while (0) -#endif -int fetchLastErrCode; -const char *fetchLastErrText; +/*** Local data **************************************************************/ + +/* + * Error messages for parser errors + */ +#define URL_MALFORMED 1 +#define URL_BAD_SCHEME 2 +#define URL_BAD_PORT 3 +static struct fetcherr _url_errlist[] = { + { URL_MALFORMED, FETCH_URL, "Malformed URL" }, + { URL_BAD_SCHEME, FETCH_URL, "Invalid URL scheme" }, + { URL_BAD_PORT, FETCH_URL, "Invalid server port" }, + { -1, FETCH_UNKNOWN, "Unknown parser error" } +}; + + +/*** Public API **************************************************************/ /* * Select the appropriate protocol for the URL scheme, and return a * read-only stream connected to the document referenced by the URL. */ FILE * -fetchGet(url_t *URL, char *flags) +fetchGet(struct url *URL, char *flags) { if (strcasecmp(URL->scheme, "file") == 0) return fetchGetFile(URL, flags); @@ -59,8 +71,10 @@ fetchGet(url_t *URL, char *flags) return fetchGetHTTP(URL, flags); else if (strcasecmp(URL->scheme, "ftp") == 0) return fetchGetFTP(URL, flags); - else return NULL; - + else { + _url_seterr(URL_BAD_SCHEME); + return NULL; + } } /* @@ -68,7 +82,7 @@ fetchGet(url_t *URL, char *flags) * write-only stream connected to the document referenced by the URL. */ FILE * -fetchPut(url_t *URL, char *flags) +fetchPut(struct url *URL, char *flags) { if (strcasecmp(URL->scheme, "file") == 0) return fetchPutFile(URL, flags); @@ -76,7 +90,29 @@ fetchPut(url_t *URL, char *flags) return fetchPutHTTP(URL, flags); else if (strcasecmp(URL->scheme, "ftp") == 0) return fetchPutFTP(URL, flags); - else return NULL; + else { + _url_seterr(URL_BAD_SCHEME); + return NULL; + } +} + +/* + * Select the appropriate protocol for the URL scheme, and return the + * size of the document referenced by the URL if it exists. + */ +int +fetchStat(struct url *URL, struct url_stat *us, char *flags) +{ + if (strcasecmp(URL->scheme, "file") == 0) + return fetchStatFile(URL, us, flags); + else if (strcasecmp(URL->scheme, "http") == 0) + return fetchStatHTTP(URL, us, flags); + else if (strcasecmp(URL->scheme, "ftp") == 0) + return fetchStatFTP(URL, us, flags); + else { + _url_seterr(URL_BAD_SCHEME); + return -1; + } } /* @@ -85,7 +121,7 @@ fetchPut(url_t *URL, char *flags) FILE * fetchGetURL(char *URL, char *flags) { - url_t *u; + struct url *u; FILE *f; if ((u = fetchParseURL(URL)) == NULL) @@ -104,7 +140,7 @@ fetchGetURL(char *URL, char *flags) FILE * fetchPutURL(char *URL, char *flags) { - url_t *u; + struct url *u; FILE *f; if ((u = fetchParseURL(URL)) == NULL) @@ -117,27 +153,50 @@ fetchPutURL(char *URL, char *flags) } /* + * Attempt to parse the given URL; if successful, call fetchStat(). + */ +int +fetchStatURL(char *URL, struct url_stat *us, char *flags) +{ + struct url *u; + int s; + + if ((u = fetchParseURL(URL)) == NULL) + return -1; + + s = fetchStat(u, us, flags); + + free(u); + return s; +} + +/* * Split an URL into components. URL syntax is: * method:[//[user[:pwd]@]host[:port]]/[document] * This almost, but not quite, RFC1738 URL syntax. */ -url_t * +struct url * fetchParseURL(char *URL) { char *p, *q; - url_t *u; + struct url *u; int i; - /* allocate url_t */ - if ((u = calloc(1, sizeof(url_t))) == NULL) + /* allocate struct url */ + if ((u = calloc(1, sizeof(struct url))) == NULL) { + errno = ENOMEM; + _fetch_syserr(); return NULL; + } /* scheme name */ for (i = 0; *URL && (*URL != ':'); URL++) if (i < URL_SCHEMELEN) u->scheme[i++] = *URL; - if (!URL[0] || (URL[1] != '/')) + if (!URL[0] || (URL[1] != '/')) { + _url_seterr(URL_BAD_SCHEME); goto ouch; + } else URL++; if (URL[1] != '/') { p = URL; @@ -171,7 +230,11 @@ fetchParseURL(char *URL) for (q = ++p; *q && (*q != '/'); q++) if (isdigit(*q)) u->port = u->port * 10 + (*q - '0'); - else return 0; /* invalid port */ + else { + /* invalid port */ + _url_seterr(URL_BAD_PORT); + goto ouch; + } while (*p && (*p != '/')) p++; } @@ -179,10 +242,13 @@ fetchParseURL(char *URL) nohost: /* document */ if (*p) { - url_t *t; + struct url *t; t = realloc(u, sizeof(*u)+strlen(p)-1); - if (t == NULL) + if (t == NULL) { + errno = ENOMEM; + _fetch_syserr(); goto ouch; + } u = t; strcpy(u->doc, p); } else { diff --git a/lib/libfetch/fetch.h b/lib/libfetch/fetch.h index cc39e36..286b253 100644 --- a/lib/libfetch/fetch.h +++ b/lib/libfetch/fetch.h @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: fetch.h,v 1.4 1998/08/17 09:30:19 des Exp $ + * $Id: fetch.h,v 1.5 1998/11/05 19:48:17 des Exp $ */ #ifndef _FETCH_H_INCLUDED @@ -34,47 +34,51 @@ #include #include +#include + #define _LIBFETCH_VER "libfetch/1.0" #define URL_SCHEMELEN 16 #define URL_USERLEN 256 #define URL_PWDLEN 256 -struct url_s { - char scheme[URL_SCHEMELEN+1]; - char user[URL_USERLEN+1]; - char pwd[URL_PWDLEN+1]; - char host[MAXHOSTNAMELEN+1]; - int port; - char doc[2]; +struct url { + char scheme[URL_SCHEMELEN+1]; + char user[URL_USERLEN+1]; + char pwd[URL_PWDLEN+1]; + char host[MAXHOSTNAMELEN+1]; + int port; + char doc[2]; }; -typedef struct url_s url_t; +struct url_stat { + off_t size; + time_t time; +}; /* FILE-specific functions */ -FILE *fetchGetFile(url_t *, char *); -FILE *fetchPutFile(url_t *, char *); +FILE *fetchGetFile(struct url *, char *); +FILE *fetchPutFile(struct url *, char *); +int fetchStatFile(struct url *, struct url_stat *, char *); /* HTTP-specific functions */ -char *fetchContentType(FILE *); -FILE *fetchGetHTTP(url_t *, char *); -FILE *fetchPutHTTP(url_t *, char *); +char *fetchContentType(FILE *); +FILE *fetchGetHTTP(struct url *, char *); +FILE *fetchPutHTTP(struct url *, char *); +int fetchStatHTTP(struct url *, struct url_stat *, char *); /* FTP-specific functions */ -FILE *fetchGetFTP(url_t *, char *); -FILE *fetchPutFTP(url_t *, char *); +FILE *fetchGetFTP(struct url *, char *); +FILE *fetchPutFTP(struct url *, char *); +int fetchStatFTP(struct url *, struct url_stat *, char *); /* Generic functions */ -int fetchConnect(char *, int); -url_t *fetchParseURL(char *); -void fetchFreeURL(url_t *); -FILE *fetchGetURL(char *, char *); -FILE *fetchPutURL(char *, char *); -FILE *fetchGet(url_t *, char *); -FILE *fetchPut(url_t *, char *); - -/* Error code and string */ -extern int fetchLastErrCode; -extern const char *fetchLastErrText; +struct url *fetchParseURL(char *); +FILE *fetchGetURL(char *, char *); +FILE *fetchPutURL(char *, char *); +int fetchStatURL(char *, struct url_stat *, char *); +FILE *fetchGet(struct url *, char *); +FILE *fetchPut(struct url *, char *); +int fetchStat(struct url *, struct url_stat *, char *); #endif diff --git a/lib/libfetch/fetch_err.et b/lib/libfetch/fetch_err.et new file mode 100644 index 0000000..233d7e7 --- /dev/null +++ b/lib/libfetch/fetch_err.et @@ -0,0 +1,49 @@ +#- +# Copyright (c) 1998 Dag-Erling Coïdan Smørgrav +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer +# in this position and unchanged. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $Id$ +# +et ftch + ec FETCH_ABORT, "Operation aborted" + ec FETCH_AUTH, "Authentication failed" + ec FETCH_DOWN, "Service unavailable" + ec FETCH_EXISTS, "File exists" + ec FETCH_FULL, "File system full" + ec FETCH_INFO, "Informational response" + ec FETCH_MEMORY, "Insufficient memory" + ec FETCH_MOVED, "File has moved" + ec FETCH_NETWORK, "Network error" + ec FETCH_OK, "No error" + ec FETCH_PROTO, "Protocol error" + ec FETCH_RESOLV, "Resolver error" + ec FETCH_SERVER, "Server error" + ec FETCH_TEMP, "Temporary error" + ec FETCH_TIMEOUT, "Operation timed out" + ec FETCH_UNAVAIL, "File is not available" + ec FETCH_UNKNOWN, "Unknown error" + ec FETCH_URL, "Invalid URL" +end diff --git a/lib/libfetch/file.c b/lib/libfetch/file.c index 0c685ef..66a681f 100644 --- a/lib/libfetch/file.c +++ b/lib/libfetch/file.c @@ -25,25 +25,54 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id$ + * $Id: file.c,v 1.1.1.1 1998/07/09 16:52:41 des Exp $ */ +#include +#include #include #include #include "fetch.h" +#include "common.h" FILE * -fetchGetFile(url_t *u, char *flags) +fetchGetFile(struct url *u, char *flags) { - flags = flags; /* unused */ - return fopen(u->doc, "r"); + FILE *f; + + f = fopen(u->doc, "r"); + + if (f == NULL) + _fetch_syserr(); + return f; } FILE * -fetchPutFile(url_t *u, char *flags) +fetchPutFile(struct url *u, char *flags) { + FILE *f; + if (strchr(flags, 'a')) - return fopen(u->doc, "a"); - else return fopen(u->doc, "w"); + f = fopen(u->doc, "a"); + else + f = fopen(u->doc, "w"); + + if (f == NULL) + _fetch_syserr(); + return f; +} + +int +fetchStatFile(struct url *u, struct url_stat *us, char *flags) +{ + struct stat sb; + + if (stat(u->doc, &sb) == -1) { + _fetch_syserr(); + return -1; + } + us->size = sb.st_size; + us->time = sb.st_mtime; + return 0; } diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c index 1899d03..81da7f8 100644 --- a/lib/libfetch/ftp.c +++ b/lib/libfetch/ftp.c @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: ftp.c,v 1.5 1998/08/17 09:30:19 des Exp $ + * $Id: ftp.c,v 1.6 1998/11/05 19:48:17 des Exp $ */ /* @@ -71,7 +71,7 @@ #include "fetch.h" #include "common.h" -#include "ftperr.c" +#include "ftperr.inc" #define FTP_DEFAULT_TO_ANONYMOUS #define FTP_ANONYMOUS_USER "ftp" @@ -88,7 +88,7 @@ #define ENDL "\r\n" -static url_t cached_host; +static struct url cached_host; static FILE *cached_socket; static char *_ftp_last_reply; @@ -101,6 +101,7 @@ _ftp_chkerr(FILE *s, int *e) { char *line; size_t len; + int err; if (e) *e = 0; @@ -122,14 +123,15 @@ _ftp_chkerr(FILE *s, int *e) if (!isdigit(line[1]) || !isdigit(line[1]) || !isdigit(line[2]) || (line[3] != ' ')) { - _ftp_seterr(-1); + _ftp_seterr(0); return -1; } - _ftp_seterr((line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0')); + err = (line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0'); + _ftp_seterr(err); if (e) - *e = fetchLastErrCode; + *e = err; return (line[0] == '2') - 1; } @@ -365,7 +367,7 @@ _ftp_disconnect(FILE *f) * Check if we're already connected */ static int -_ftp_isconnected(url_t *url) +_ftp_isconnected(struct url *url) { return (cached_socket && (strcmp(url->host, cached_host.host) == 0) @@ -378,7 +380,7 @@ _ftp_isconnected(url_t *url) * FTP session */ static FILE * -fetchXxxFTP(url_t *url, char *oper, char *mode, char *flags) +fetchXxxFTP(struct url *url, char *oper, char *mode, char *flags) { FILE *cf = NULL; int e; @@ -402,7 +404,7 @@ fetchXxxFTP(url_t *url, char *oper, char *mode, char *flags) if (cached_socket) _ftp_disconnect(cached_socket); cached_socket = cf; - memcpy(&cached_host, url, sizeof(url_t)); + memcpy(&cached_host, url, sizeof(struct url)); } /* initiate the transfer */ @@ -413,15 +415,24 @@ fetchXxxFTP(url_t *url, char *oper, char *mode, char *flags) * Itsy bitsy teeny weenie */ FILE * -fetchGetFTP(url_t *url, char *flags) +fetchGetFTP(struct url *url, char *flags) { return fetchXxxFTP(url, "RETR", "r", flags); } FILE * -fetchPutFTP(url_t *url, char *flags) +fetchPutFTP(struct url *url, char *flags) { if (flags && strchr(flags, 'a')) return fetchXxxFTP(url, "APPE", "w", flags); else return fetchXxxFTP(url, "STOR", "w", flags); } + +extern void warnx(char *fmt, ...); +int +fetchStatFTP(struct url *url, struct url_stat *us, char *flags) +{ + warnx("fetchStatFTP(): not implemented"); + return -1; +} + diff --git a/lib/libfetch/ftp.errors b/lib/libfetch/ftp.errors index 53a87f0..d7816d2 100644 --- a/lib/libfetch/ftp.errors +++ b/lib/libfetch/ftp.errors @@ -1,44 +1,44 @@ -# $Id: ftp.errors,v 1.3 1997/02/22 15:06:47 peter Exp $ +# $Id: ftp.errors,v 1.1.1.1 1998/07/09 16:52:43 des Exp $ # # This list is taken from RFC 959. # It probably needs a going over. # -110 Restart marker reply -120 Service ready in a few minutes -125 Data connection already open; transfer starting -150 File status okay; about to open data connection -200 Command okay -202 Command not implemented, superfluous at this site -211 System status, or system help reply -212 Directory status -213 File status -214 Help message -215 Set system type -220 Service ready for new user -221 Service closing control connection -225 Data connection open; no transfer in progress -226 Requested file action successful -227 Entering Passive Mode -230 User logged in, proceed -250 Requested file action okay, completed -257 File/directory created -331 User name okay, need password -332 Need account for login -350 Requested file action pending further information -421 Service not available, closing control connection -425 Can't open data connection -426 Connection closed; transfer aborted -450 File unavailable (e.g., file busy) -451 Requested action aborted: local error in processing -452 Insufficient storage space in system -500 Syntax error, command unrecognized -501 Syntax error in parameters or arguments -502 Command not implemented -503 Bad sequence of commands -504 Command not implemented for that parameter -530 Not logged in -532 Need account for storing files -550 File unavailable (e.g., file not found, no access) -551 Requested action aborted. Page type unknown -552 Exceeded storage allocation -553 File name not allowed +110 OK Restart marker reply +120 TEMP Service ready in a few minutes +125 OK Data connection already open; transfer starting +150 OK File status okay; about to open data connection +200 OK Command okay +202 PROTO Command not implemented, superfluous at this site +211 INFO System status, or system help reply +212 INFO Directory status +213 INFO File status +214 INFO Help message +215 INFO Set system type +220 OK Service ready for new user +221 OK Service closing control connection +225 OK Data connection open; no transfer in progress +226 OK Requested file action successful +227 OK Entering Passive Mode +230 OK User logged in, proceed +250 OK Requested file action okay, completed +257 OK File/directory created +331 AUTH User name okay, need password +332 AUTH Need account for login +350 OK Requested file action pending further information +421 DOWN Service not available, closing control connection +425 NETWORK Can't open data connection +426 ABORT Connection closed; transfer aborted +450 UNAVAIL File unavailable (e.g., file busy) +451 SERVER Requested action aborted: local error in processing +452 FULL Insufficient storage space in system +500 PROTO Syntax error, command unrecognized +501 PROTO Syntax error in parameters or arguments +502 PROTO Command not implemented +503 PROTO Bad sequence of commands +504 PROTO Command not implemented for that parameter +530 AUTH Not logged in +532 AUTH Need account for storing files +550 UNAVAIL File unavailable (e.g., file not found, no access) +551 PROTO Requested action aborted. Page type unknown +552 FULL Exceeded storage allocation +553 EXISTS File name not allowed diff --git a/lib/libfetch/http.c b/lib/libfetch/http.c index aea3d1d..973584c 100644 --- a/lib/libfetch/http.c +++ b/lib/libfetch/http.c @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: http.c,v 1.5 1998/08/17 09:30:19 des Exp $ + * $Id: http.c,v 1.6 1998/11/05 19:48:17 des Exp $ */ /* @@ -78,7 +78,7 @@ #include "fetch.h" #include "common.h" -#include "httperr.c" +#include "httperr.inc" #ifndef NDEBUG #define DEBUG(x) do x; while (0) @@ -300,10 +300,10 @@ _http_auth(char *usr, char *pwd) } /* - * retrieve a file by HTTP + * Retrieve a file by HTTP */ FILE * -fetchGetHTTP(url_t *URL, char *flags) +fetchGetHTTP(struct url *URL, char *flags) { int sd = -1, err, i, enc = ENC_NONE; struct cookie *c; @@ -389,8 +389,7 @@ fetchGetHTTP(url_t *URL, char *flags) /* add code to handle redirects later */ if (err != 200) { - fetchLastErrCode = err; - fetchLastErrText = _http_errstring(err); + _http_seterr(err); goto fouch; } @@ -452,8 +451,18 @@ fouch: } FILE * -fetchPutHTTP(url_t *URL, char *flags) +fetchPutHTTP(struct url *URL, char *flags) { warnx("fetchPutHTTP(): not implemented"); return NULL; } + +/* + * Get an HTTP document's metadata + */ +int +fetchStatHTTP(struct url *url, struct url_stat *us, char *flags) +{ + warnx("fetchStatHTTP(): not implemented"); + return -1; +} diff --git a/lib/libfetch/http.errors b/lib/libfetch/http.errors index c0e3539..26907d5 100644 --- a/lib/libfetch/http.errors +++ b/lib/libfetch/http.errors @@ -1,41 +1,41 @@ -# $Id$ +# $Id: http.errors,v 1.1.1.1 1998/07/09 16:52:44 des Exp $ # # This list is taken from RFC 2068. # -100 Continue -101 Switching Protocols -200 OK -201 Created -202 Accepted -203 Non-Authoritative Information -204 No Content -205 Reset Content -206 Partial Content -300 Multiple Choices -301 Moved Permanently -302 Moved Temporarily -303 See Other -304 Not Modified -305 Use Proxy -400 Bad Request -401 Unauthorized -402 Payment Required -403 Forbidden -404 Not Found -405 Method Not Allowed -406 Not Acceptable -407 Proxy Authentication Required -408 Request Time-out -409 Conflict -410 Gone -411 Length Required -412 Precondition Failed -413 Request Entity Too Large -414 Request-URI Too Large -415 Unsupported Media Type -500 Internal Server Error -501 Not Implemented -502 Bad Gateway -503 Service Unavailable -504 Gateway Time-out -505 HTTP Version not supported +100 OK Continue +101 OK Switching Protocols +200 OK OK +201 OK Created +202 OK Accepted +203 INFO Non-Authoritative Information +204 OK No Content +205 OK Reset Content +206 OK Partial Content +300 MOVED Multiple Choices +301 MOVED Moved Permanently +302 MOVED Moved Temporarily +303 MOVED See Other +304 OK Not Modified +305 INFO Use Proxy +400 PROTO Bad Request +401 AUTH Unauthorized +402 AUTH Payment Required +403 AUTH Forbidden +404 UNAVAIL Not Found +405 PROTO Method Not Allowed +406 PROTO Not Acceptable +407 AUTH Proxy Authentication Required +408 TIMEOUT Request Time-out +409 EXISTS Conflict +410 UNAVAIL Gone +411 PROTO Length Required +412 SERVER Precondition Failed +413 PROTO Request Entity Too Large +414 PROTO Request-URI Too Large +415 PROTO Unsupported Media Type +500 SERVER Internal Server Error +501 PROTO Not Implemented +502 SERVER Bad Gateway +503 TEMP Service Unavailable +504 TIMEOUT Gateway Time-out +505 PROTO HTTP Version not supported -- cgit v1.1