?? ftpclient.c
字號(hào):
/* vi: set sw=4 ts=4: *//* * ftpget * * Mini implementation of FTP to retrieve a remote file. * * Copyright (C) 2002 Jeff Angielski, The PTR Group <jeff@theptrgroup.com> * Copyright (C) 2002 Glenn McGrath <bug1@iinet.net.au> * * Based on wget.c by Chip Rosenthal Covad Communications * <chip@laserlink.net> * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. *///#include <ctype.h>#include <dirent.h>#include <errno.h>#include <fcntl.h>#include <inttypes.h>#include <mntent.h>#include <netdb.h>#include <setjmp.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <stddef.h>#include <string.h>#include <strings.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <sys/socket.h>#include <sys/stat.h>#include <sys/statfs.h>#include <sys/time.h>#include <sys/types.h>#include <sys/wait.h>#include <termios.h>#include <time.h>#include <unistd.h>#include <utime.h>#include <getopt.h>#include <limits.h>#define FTP_HEAD_SIZE 512/* We hijack this constant to mean something else *//* It doesn't hurt because we will remove this bit anyway */#define DIE_ON_ERROR AI_CANONNAME#define isdigit(a) ((unsigned)((a) - '0') <= 9)//#define xatou(rest) xatoull##rest#define LONE_DASH(s) ((s)[0] == '-' && !(s)[1])#define NOT_LONE_DASH(s) ((s)[0] != '-' || (s)[1])#define ENABLE_FEATURE_IPV6 0#define type long#define xstrtou(rest) xstrtoul##rest#define xstrto(rest) xstrtol##rest#define xatou(rest) xatoul##rest#define xato(rest) xatol##rest#define XSTR_UTYPE_MAX ULONG_MAX#define XSTR_TYPE_MAX LONG_MAX#define XSTR_TYPE_MIN LONG_MIN#define XSTR_STRTOU strtoul#include "ftp_template.c"#define bb_error_msg_and_die(fmt,args...) { \ printf ("%s( %d): "fmt"\n" , __FILE__,__LINE__, ##args); \ exit(-1); \ }#define bb_error_msg(fmt,args...) printf ("%s( %d): "fmt , __FILE__,__LINE__, ##args)typedef signed char smallint;typedef struct len_and_sockaddr { socklen_t len; union { struct sockaddr sa; struct sockaddr_in sin; };} len_and_sockaddr;typedef struct ftp_host_info_s { const char *user; const char *password; struct len_and_sockaddr *lsa;} ftp_host_info_t;static smallint verbose_flag=1;static smallint do_continue;char * safe_strncpy(char *dst, const char *src, size_t size){ if (!size) return dst; dst[--size] = '\0'; return strncpy(dst, src, size);}uint16_t xatou16(const char *numstr){ return xatoul_range(numstr, 0, 0xffff);}void set_nport(len_and_sockaddr *lsa, unsigned port){ if (lsa->sa.sa_family == AF_INET) { lsa->sin.sin_port = port; return; } /* What? UNIX socket? IPX?? :) */}void *xmalloc(int size){ void *ptr; ptr = malloc(size); if (ptr == NULL && size != 0) bb_error_msg_and_die("memory exhausted"); return ptr;}static len_and_sockaddr* str2sockaddr( const char *host, int port, int ai_flags){ int rc; len_and_sockaddr *r = NULL; struct addrinfo *result = NULL; const char *org_host = host; /* only for error msg */ const char *cp; struct addrinfo hint; /* Ugly parsing of host:addr */ if (ENABLE_FEATURE_IPV6 && host[0] == '[') { host++; cp = strchr(host, ']'); if (!cp || cp[1] != ':') /* Malformed: must have [xx]:nn */ bb_error_msg_and_die("bad address '%s'", org_host); //return r; /* return NULL */ } else { cp = strrchr(host, ':'); if (ENABLE_FEATURE_IPV6 && cp && strchr(host, ':') != cp) { /* There is more than one ':' (e.g. "::1") */ cp = NULL; /* it's not a port spec */ } } if (cp) { int sz = cp - host + 1; host = safe_strncpy(alloca(sz), host, sz); if (ENABLE_FEATURE_IPV6 && *cp != ':') cp++; /* skip ']' */ cp++; /* skip ':' */ port = xatou16(cp); } memset(&hint, 0 , sizeof(hint));#if !ENABLE_FEATURE_IPV6 hint.ai_family = AF_INET; /* do not try to find IPv6 */#else hint.ai_family = af;#endif /* Needed. Or else we will get each address thrice (or more) * for each possible socket type (tcp,udp,raw...): */ hint.ai_socktype = SOCK_STREAM; hint.ai_flags = ai_flags & ~DIE_ON_ERROR; rc = getaddrinfo(host, NULL, &hint, &result); if (rc || !result) { bb_error_msg("bad address '%s'", org_host); if (ai_flags & DIE_ON_ERROR) exit(-1); goto ret; } r = xmalloc(offsetof(len_and_sockaddr, sa) + result->ai_addrlen); r->len = result->ai_addrlen; memcpy(&r->sa, result->ai_addr, result->ai_addrlen); set_nport(r, htons(port)); ret: freeaddrinfo(result); return r;}int xsocket(int nDomain, int nType, int nProtocol){ int r; r = socket(nDomain, nType, nProtocol); if (r < 0) { /* Hijack vaguely related config option */ bb_error_msg_and_die("socket"); } return r;}void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen){ if (connect(s, s_addr, addrlen) < 0) { close(s); if (s_addr->sa_family == AF_INET) bb_error_msg_and_die("%s (%s)", "cannot connect to remote host", inet_ntoa(((struct sockaddr_in *)s_addr)->sin_addr)); //bb_error_msg_and_die("cannot connect to remote host"); }}int xconnect_stream(const len_and_sockaddr *lsa){ int fd = xsocket(lsa->sa.sa_family, SOCK_STREAM, 0); xconnect(fd, &lsa->sa, lsa->len); return fd;}int xopen(const char *pathname, int flags, int mode){ int ret; ret = open(pathname, flags, mode); if (ret < 0) { bb_error_msg_and_die("can't open '%s'", pathname); } return ret;}ssize_t safe_read(int fd, void *buf, size_t count){ ssize_t n; do { n = read(fd, buf, count); } while (n < 0 && errno == EINTR); return n;}ssize_t safe_write(int fd, const void *buf, size_t count){ ssize_t n; do { n = write(fd, buf, count); } while (n < 0 && errno == EINTR); return n;}/* * Write all of the supplied buffer out to a file. * This does multiple writes as necessary. * Returns the amount written, or -1 on an error. */ssize_t full_write(int fd, const void *buf, size_t len){ ssize_t cc; ssize_t total; total = 0; while (len) { cc = safe_write(fd, buf, len); if (cc < 0) return cc; /* write() returns -1 on failure. */ total += cc; buf = ((const char *)buf) + cc; len -= cc; } return total;}static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size){ int status = -1; off_t total = 0; char buffer[BUFSIZ]; if (src_fd < 0) goto out; if (!size) { size = BUFSIZ; status = 1; /* copy until eof */ } while (1) { ssize_t rd; rd = safe_read(src_fd, buffer, size > BUFSIZ ? BUFSIZ : size);//printf("-----rd =%d----\n", rd); if (!rd) { /* eof - all done */ status = 0; break; } if (rd < 0) { //bb_error_msg(bb_msg_read_error); break; } /* dst_fd == -1 is a fake, else... */ if (dst_fd >= 0) { ssize_t wr = full_write(dst_fd, buffer, rd); if (wr < rd) { //bb_error_msg(bb_msg_write_error); break; } } total += rd; if (status < 0) { /* if we aren't copying till EOF... */ size -= rd; if (!size) { /* 'size' bytes copied - all done */ status = 0; break; } } } out: return status ? -1 : total;}off_t bb_copyfd_size(int fd1, int fd2, off_t size){ if (size) { return bb_full_fd_action(fd1, fd2, size); } return 0;}off_t bb_copyfd_eof(int fd1, int fd2){ return bb_full_fd_action(fd1, fd2, 0);}static void ftp_die(const char *msg, const char *remote){ /* Guard against garbage from remote server */ const char *cp = remote; while (*cp >= ' ' && *cp < '\x7f') cp++; bb_error_msg_and_die("unexpected server response%s%s: %.*s", msg ? " to " : "", msg ? msg : "", (int)(cp - remote), remote); exit(-1);}static int ftpcmd(const char *s1, const char *s2, FILE *stream, char *buf){ unsigned n; if (verbose_flag) { bb_error_msg("cmd %s %s", s1, s2); } if (s1) { if (s2) { fprintf(stream, "%s %s\r\n", s1, s2); } else { fprintf(stream, "%s\r\n", s1); } } do { char *buf_ptr; if (fgets(buf, 510, stream) == NULL) { bb_error_msg_and_die("fgets"); } buf_ptr = strstr(buf, "\r\n"); if (buf_ptr) { *buf_ptr = '\0'; printf("--%s\n", buf); } } while (!isdigit(buf[0]) || buf[3] != ' '); buf[3] = '\0'; //n = xatou(buf); n = atol(buf); buf[3] = ' '; return n;}static int xconnect_ftpdata(ftp_host_info_t *server, char *buf){ char *buf_ptr; unsigned short port_num; /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage] * Server's IP is N1.N2.N3.N4 (we ignore it) * Server's port for data connection is P1*256+P2 */ buf_ptr = strrchr(buf, ')'); if (buf_ptr) *buf_ptr = '\0'; buf_ptr = strrchr(buf, ','); *buf_ptr = '\0'; port_num = xatoul_range(buf_ptr + 1, 0, 255); buf_ptr = strrchr(buf, ','); *buf_ptr = '\0'; port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256; set_nport(server->lsa, htons(port_num)); return xconnect_stream(server->lsa);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -