diff options
author | cvs2svn <cvs2svn@FreeBSD.org> | 1999-01-21 00:55:32 +0000 |
---|---|---|
committer | cvs2svn <cvs2svn@FreeBSD.org> | 1999-01-21 00:55:32 +0000 |
commit | 76b5366091f76c9bc73570149ef5055648fc2c39 (patch) | |
tree | 590d020e0f2a5bea6e09d66d951a674443b21d67 /lib/libfetch/ftp.c | |
parent | 4b4d01da6f07f7754ff6a6e4f5223e9f0984d1a6 (diff) |
Notes
Diffstat (limited to 'lib/libfetch/ftp.c')
-rw-r--r-- | lib/libfetch/ftp.c | 280 |
1 files changed, 110 insertions, 170 deletions
diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c index 10e27b45ae93..d66b7c3f7494 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.11 1998/12/18 14:32:48 des Exp $ + * $Id: ftp.c,v 1.4 1998/07/12 22:34:39 des Exp $ */ /* @@ -55,30 +55,30 @@ * */ -#include <sys/param.h> +#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> +#include <sys/errno.h> #include <ctype.h> +#include <errno.h> +#include <netdb.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <time.h> #include <unistd.h> #include "fetch.h" -#include "common.h" -#include "ftperr.h" +#include "ftperr.c" +#define FTP_DEFAULT_TO_ANONYMOUS #define FTP_ANONYMOUS_USER "ftp" #define FTP_ANONYMOUS_PASSWORD "ftp" #define FTP_DEFAULT_PORT 21 #define FTP_OPEN_DATA_CONNECTION 150 #define FTP_OK 200 -#define FTP_FILE_STATUS 213 -#define FTP_SERVICE_READY 220 #define FTP_PASSIVE_MODE 227 #define FTP_LOGGED_IN 230 #define FTP_FILE_ACTION_OK 250 @@ -87,44 +87,84 @@ #define ENDL "\r\n" -static struct url cached_host; +static url_t cached_host; static FILE *cached_socket; -static char _ftp_last_reply[1024]; +static char *_ftp_last_reply; + +/* + * Map error code to string + */ +static const char * +_ftp_errstring(int e) +{ + struct ftperr *p = _ftp_errlist; + + while ((p->num != -1) && (p->num != e)) + p++; + + return p->string; +} + +/* + * Set error code + */ +static void +_ftp_seterr(int e) +{ + fetchLastErrCode = e; + fetchLastErrText = _ftp_errstring(e); +} + +/* + * Set error code according to errno + */ +static void +_ftp_syserr(void) +{ + fetchLastErrCode = errno; + fetchLastErrText = strerror(errno); +} /* * Get server response, check that first digit is a '2' */ static int -_ftp_chkerr(FILE *s) +_ftp_chkerr(FILE *s, int *e) { char *line; size_t len; + if (e) + *e = 0; + do { if (((line = fgetln(s, &len)) == NULL) || (len < 4)) { - _fetch_syserr(); + _ftp_syserr(); return -1; } - } while (len >= 4 && line[3] == '-'); + } while (line[3] == '-'); - while (len && isspace(line[len-1])) - len--; - snprintf(_ftp_last_reply, sizeof(_ftp_last_reply), - "%*.*s", (int)len, (int)len, line); + _ftp_last_reply = line; #ifndef NDEBUG fprintf(stderr, "\033[1m<<< "); - fprintf(stderr, "%*.*s\n", (int)len, (int)len, line); + fprintf(stderr, "%*.*s", (int)len, (int)len, line); fprintf(stderr, "\033[m"); #endif - if (len < 4 || !isdigit(line[1]) || !isdigit(line[1]) + if (!isdigit(line[1]) || !isdigit(line[1]) || !isdigit(line[2]) || (line[3] != ' ')) { + _ftp_seterr(-1); return -1; } - return (line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0'); + _ftp_seterr((line[0] - '0') * 100 + (line[1] - '0') * 10 + (line[2] - '0')); + + if (e) + *e = fetchLastErrCode; + + return (line[0] == '2') - 1; } /* @@ -134,6 +174,7 @@ static int _ftp_cmd(FILE *f, char *fmt, ...) { va_list ap; + int e; va_start(ap, fmt); vfprintf(f, fmt, ap); @@ -144,7 +185,8 @@ _ftp_cmd(FILE *f, char *fmt, ...) #endif va_end(ap); - return _ftp_chkerr(f); + _ftp_chkerr(f, &e); + return e; } /* @@ -154,31 +196,28 @@ static FILE * _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv) { struct sockaddr_in sin; - int e, sd = -1, l; + int sd = -1, l; char *s; FILE *df; /* change directory */ if (((s = strrchr(file, '/')) != NULL) && (s != file)) { *s = 0; - if ((e = _ftp_cmd(cf, "CWD %s" ENDL, file)) != FTP_FILE_ACTION_OK) { + if (_ftp_cmd(cf, "CWD %s" ENDL, file) != FTP_FILE_ACTION_OK) { *s = '/'; - _ftp_seterr(e); return NULL; } *s++ = '/'; } else { - if ((e = _ftp_cmd(cf, "CWD /" ENDL)) != FTP_FILE_ACTION_OK) { - _ftp_seterr(e); + if (_ftp_cmd(cf, "CWD /" ENDL) != FTP_FILE_ACTION_OK) return NULL; - } } /* s now points to file name */ /* open data socket */ if ((sd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { - _fetch_syserr(); + _ftp_syserr(); return NULL; } @@ -188,7 +227,7 @@ _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv) int i; /* send PASV command */ - if ((e = _ftp_cmd(cf, "PASV" ENDL)) != FTP_PASSIVE_MODE) + if (_ftp_cmd(cf, "PASV" ENDL) != FTP_PASSIVE_MODE) goto ouch; /* find address and port number. The reply to the PASV command @@ -213,8 +252,7 @@ _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv) goto sysouch; /* make the server initiate the transfer */ - e = _ftp_cmd(cf, "%s %s" ENDL, oper, s); - if (e != FTP_OPEN_DATA_CONNECTION) + if (_ftp_cmd(cf, "%s %s" ENDL, oper, s) != FTP_OPEN_DATA_CONNECTION) goto ouch; } else { @@ -237,16 +275,13 @@ _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv) goto sysouch; a = ntohl(sin.sin_addr.s_addr); p = ntohs(sin.sin_port); - e = _ftp_cmd(cf, "PORT %d,%d,%d,%d,%d,%d" ENDL, - (a >> 24) & 0xff, (a >> 16) & 0xff, - (a >> 8) & 0xff, a & 0xff, - (p >> 8) & 0xff, p & 0xff); - if (e != FTP_OK) + if (_ftp_cmd(cf, "PORT %d,%d,%d,%d,%d,%d" ENDL, + (a >> 24) & 0xff, (a >> 16) & 0xff, (a >> 8) & 0xff, a & 0xff, + (p >> 8) & 0xff, p & 0xff) != FTP_OK) goto ouch; /* make the server initiate the transfer */ - e = _ftp_cmd(cf, "%s %s" ENDL, oper, s); - if (e != FTP_OPEN_DATA_CONNECTION) + if (_ftp_cmd(cf, "%s %s" ENDL, oper, s) != FTP_OPEN_DATA_CONNECTION) goto ouch; /* accept the incoming connection and go to town */ @@ -261,12 +296,8 @@ _ftp_transfer(FILE *cf, char *oper, char *file, char *mode, int pasv) return df; sysouch: - _fetch_syserr(); - close(sd); - return NULL; - + _ftp_syserr(); ouch: - _ftp_seterr(e); close(sd); return NULL; } @@ -275,7 +306,7 @@ ouch: * Log on to FTP server */ static FILE * -_ftp_connect(char *host, int port, char *user, char *pwd, int verbose) +_ftp_connect(char *host, int port, char *user, char *pwd) { int sd, e, pp = FTP_DEFAULT_PORT; char *p, *q; @@ -289,29 +320,28 @@ _ftp_connect(char *host, int port, char *user, char *pwd, int verbose) } if (q) *q = 0; - sd = _fetch_connect(p, pp, verbose); + sd = fetchConnect(p, pp); if (q) *q = ':'; } else { /* no proxy, go straight to target */ - sd = _fetch_connect(host, port, verbose); + sd = fetchConnect(host, port); } /* check connection */ if (sd == -1) { - _fetch_syserr(); + _ftp_syserr(); return NULL; } /* streams make life easier */ if ((f = fdopen(sd, "r+")) == NULL) { - _fetch_syserr(); - close(sd); - return NULL; + _ftp_syserr(); + goto ouch; } /* expect welcome message */ - if ((e = _ftp_chkerr(f)) != FTP_SERVICE_READY) + if (_ftp_chkerr(f, NULL) == -1) goto fouch; /* send user name and password */ @@ -329,7 +359,7 @@ _ftp_connect(char *host, int port, char *user, char *pwd, int verbose) /* did the server request an account? */ if (e == FTP_NEED_ACCOUNT) - goto fouch; + /* help! */ ; /* we should be done by now */ if (e != FTP_LOGGED_IN) @@ -337,17 +367,19 @@ _ftp_connect(char *host, int port, char *user, char *pwd, int verbose) /* might as well select mode and type at once */ #ifdef FTP_FORCE_STREAM_MODE - if ((e = _ftp_cmd(f, "MODE S" ENDL)) != FTP_OK) /* default is S */ - goto fouch; + if (_ftp_cmd(f, "MODE S" ENDL) != FTP_OK) /* default is S */ + goto ouch; #endif - if ((e = _ftp_cmd(f, "TYPE I" ENDL)) != FTP_OK) /* default is A */ - goto fouch; + if (_ftp_cmd(f, "TYPE I" ENDL) != FTP_OK) /* default is A */ + goto ouch; /* done */ return f; +ouch: + close(sd); + return NULL; fouch: - _ftp_seterr(e); fclose(f); return NULL; } @@ -358,7 +390,7 @@ fouch: static void _ftp_disconnect(FILE *f) { - (void)_ftp_cmd(f, "QUIT" ENDL); + _ftp_cmd(f, "QUIT" ENDL); fclose(f); } @@ -366,7 +398,7 @@ _ftp_disconnect(FILE *f) * Check if we're already connected */ static int -_ftp_isconnected(struct url *url) +_ftp_isconnected(url_t *url) { return (cached_socket && (strcmp(url->host, cached_host.host) == 0) @@ -376,145 +408,53 @@ _ftp_isconnected(struct url *url) } /* - * Check the cache, reconnect if no luck + * FTP session */ static FILE * -_ftp_cached_connect(struct url *url, char *flags) +fetchXxxFTP(url_t *url, char *oper, char *mode, char *flags) { - FILE *cf; + FILE *cf = NULL; + int e; - cf = NULL; - /* set default port */ if (!url->port) url->port = FTP_DEFAULT_PORT; - /* try to use previously cached connection */ - if (_ftp_isconnected(url)) - if (_ftp_cmd(cached_socket, "NOOP" ENDL) != -1) + /* try to use previously cached connection; there should be a 226 waiting */ + if (_ftp_isconnected(url)) { + _ftp_chkerr(cached_socket, &e); + if (e > 0) cf = cached_socket; + } /* connect to server */ if (!cf) { - cf = _ftp_connect(url->host, url->port, url->user, url->pwd, - (strchr(flags, 'v') != NULL)); + cf = _ftp_connect(url->host, url->port, url->user, url->pwd); if (!cf) return NULL; if (cached_socket) _ftp_disconnect(cached_socket); cached_socket = cf; - memcpy(&cached_host, url, sizeof(struct url)); + memcpy(&cached_host, url, sizeof(url_t)); } - return cf; -} - -/* - * Get file - */ -FILE * -fetchGetFTP(struct url *url, char *flags) -{ - FILE *cf; - - /* connect to server */ - if ((cf = _ftp_cached_connect(url, flags)) == NULL) - return NULL; - /* initiate the transfer */ - return _ftp_transfer(cf, "RETR", url->doc, "r", - (flags && strchr(flags, 'p'))); + return _ftp_transfer(cf, oper, url->doc, mode, (flags && strchr(flags, 'p'))); } /* - * Put file + * Itsy bitsy teeny weenie */ FILE * -fetchPutFTP(struct url *url, char *flags) -{ - FILE *cf; - - /* connect to server */ - if ((cf = _ftp_cached_connect(url, flags)) == NULL) - return NULL; - - /* initiate the transfer */ - return _ftp_transfer(cf, (flags && strchr(flags, 'a')) ? "APPE" : "STOR", - url->doc, "w", (flags && strchr(flags, 'p'))); -} - -/* - * Get file stats - */ -int -fetchStatFTP(struct url *url, struct url_stat *us, char *flags) +fetchGetFTP(url_t *url, char *flags) { - FILE *cf; - char *ln, *s; - struct tm tm; - time_t t; - int e; - - /* connect to server */ - if ((cf = _ftp_cached_connect(url, flags)) == NULL) - return -1; - - /* change directory */ - if (((s = strrchr(url->doc, '/')) != NULL) && (s != url->doc)) { - *s = 0; - if ((e = _ftp_cmd(cf, "CWD %s" ENDL, url->doc)) != FTP_FILE_ACTION_OK) { - *s = '/'; - goto ouch; - } - *s++ = '/'; - } else { - if ((e = _ftp_cmd(cf, "CWD /" ENDL)) != FTP_FILE_ACTION_OK) - goto ouch; - } - - /* s now points to file name */ - - if (_ftp_cmd(cf, "SIZE %s" ENDL, s) != FTP_FILE_STATUS) - goto ouch; - for (ln = _ftp_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(999); /* XXX should signal a FETCH_PROTO error */ - return -1; - } - - if ((e = _ftp_cmd(cf, "MDTM %s" ENDL, s)) != FTP_FILE_STATUS) - goto ouch; - for (ln = _ftp_last_reply + 4; *ln && isspace(*ln); ln++) - /* nothing */ ; - t = time(NULL); - us->mtime = localtime(&t)->tm_gmtoff; - 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); - /* XXX should check the return value from sscanf */ - tm.tm_mon--; - tm.tm_year -= 1900; - tm.tm_isdst = -1; - tm.tm_gmtoff = 0; - us->mtime += mktime(&tm); - us->atime = us->mtime; - return 0; - -ouch: - _ftp_seterr(e); - return -1; + return fetchXxxFTP(url, "RETR", "r", flags); } -/* - * List a directory - */ -extern void warnx(char *, ...); -struct url_ent * -fetchListFTP(struct url *url, char *flags) +FILE * +fetchPutFTP(url_t *url, char *flags) { - warnx("fetchListFTP(): not implemented"); - return NULL; + if (flags && strchr(flags, 'a')) + return fetchXxxFTP(url, "APPE", "w", flags); + else return fetchXxxFTP(url, "STOR", "w", flags); } |