⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftp.c

📁 UNIX环境下命令行FTP/SFTP工具源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $Id: ftp.c,v 1.37 2004/05/20 11:10:52 mhe Exp $ * * ftp.c -- low(er) level FTP stuff * * Yet Another FTP Client * Copyright (C) 1998-2001, Martin Hedenfalk <mhe@stacken.kth.se> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. See COPYING for more details. */#include "syshdr.h"#include "ftp.h"#include "xmalloc.h"#include "strq.h"#include "gvars.h"#include "ssh_cmd.h"#include "sftp-common.h"#include "args.h"/* in cmd.c */void exit_yafc(void);/* in get.c */char *make_unique_filename(const char *path);/* in tag.c */void save_taglist(const char *alt_filename);/* in bookmark.c */void auto_create_bookmark(void);Ftp *ftp = 0;Ftp *ftp_create(void){    Ftp *ftp;    ftp = (Ftp *)xmalloc(sizeof(Ftp));    ftp->verbosity = vbCommand;    ftp->tmp_verbosity = vbUnset;    ftp->last_mkpath = 0;    ftp->cache = list_new((listfunc)rdir_destroy);    ftp->dirs_to_flush = list_new((listfunc)free);    ftp->reply_timeout = 30;    ftp->open_timeout = 30;    ftp->taglist = list_new((listfunc)rfile_destroy);#ifdef SECFTP    ftp->app_data = 0;/*  ftp->in_buffer = 0;*//*  ftp->out_buffer = 0;*/#endif    ftp->LIST_type = ltUnknown;    ftp->ssh_id = 1;    ftp->ssh_args = args_create();    return ftp;}int ftp_set_trace(const char *filename){    if(gvLogfp)        /* already opened */        return 0;    gvLogfp = fopen(filename, "w");    if(gvLogfp) {        time_t now = time(0);        setbuf(gvLogfp, 0); /* change buffering */        fprintf(gvLogfp, "yafc " VERSION " trace file started %s\n",                ctime(&now));        return 0;    }    return -1;}void ftp_vtrace(const char *fmt, va_list ap){    if(gvLogfp)        vfprintf(gvLogfp, fmt, ap);}void ftp_trace(const char *fmt, ...){    va_list ap;    va_start(ap, fmt);    ftp_vtrace(fmt, ap);    va_end(ap);}void ftp_err(const char *fmt, ...){    va_list ap;    va_start(ap, fmt);    vfprintf(stderr, fmt, ap);    va_end(ap);    va_start(ap, fmt);    ftp_vtrace(fmt, ap);    va_end(ap);}void ftp_use(Ftp *useftp){    ftp = useftp;}void ftp_destroy(Ftp *ftp){    if(!ftp)        return;    list_free(ftp->dirs_to_flush);    list_free(ftp->cache);    ftp->cache = ftp->dirs_to_flush = 0;    host_destroy(ftp->host);    sock_destroy(ftp->data);    sock_destroy(ftp->ctrl);    ftp->host = 0;    ftp->data = ftp->ctrl = 0;    url_destroy(ftp->url);    ftp->url = 0;    free(ftp->homedir);    free(ftp->curdir);    free(ftp->prevdir);    list_free(ftp->taglist);    args_destroy(ftp->ssh_args);    ftp->ssh_args = 0;#ifdef SECFTP    sec_end();#endif    free(ftp);}static int proxy_type(url_t *url){    listitem *li;    char *url_domain;    if(gvProxyType == 0 || url->noproxy == true || gvProxyUrl == 0)        return 0;    url_domain = strrchr(url->hostname, '.');    for(li=gvProxyExclude->first; li; li=li->next) {        char *xhost = (char *)li->data;        if(!xhost)            /* should not happen */            continue;        if(xhost[0] == '.' && url_domain) {            if(strcasecmp(url_domain, xhost) == 0)                /* exclude domain names */                return 0;        }        if(strcasecmp(xhost, "localnet") == 0 && url_domain == 0)            /* exclude unqualified hosts */            return 0;        if(strcasecmp(xhost, url->hostname) == 0)            /* exclude hostnames */            return 0;    }    return gvProxyType;}void ftp_reset_vars(void){    sock_destroy(ftp->data);    ftp->data = 0;    sock_destroy(ftp->ctrl);    ftp->ctrl = 0;    host_destroy(ftp->host);    ftp->host = 0;    if(ftp->ssh_pid) {        ftp->ssh_pid = 0;        close(ftp->ssh_in);        close(ftp->ssh_out);        ftp->ssh_id = 0;    }    args_clear(ftp->ssh_args);    url_destroy(ftp->url);    ftp->url = 0;    ftp->connected = false;    ftp->loggedin = false;    ftp->has_mdtm_command = true;    ftp->has_size_command = true;    ftp->has_pasv_command = true;    ftp->has_stou_command = true;    ftp->has_site_chmod_command = true;    ftp->has_site_idle_command = true;    ftp->has_mlsd_command = true;    list_free(ftp->dirs_to_flush);    ftp->dirs_to_flush = list_new((listfunc)free);    list_free(ftp->cache);    ftp->cache = list_new((listfunc)rdir_destroy);    /* don't assume server is in ascii mode initially even if RFC says so */    ftp->prev_type = '?';    ftp->code = ctNone;    ftp->fullcode = 0;    ftp->reply_timeout = gvCommandTimeout;    free(ftp->last_mkpath);    ftp->last_mkpath = 0;#ifdef SECFTP    sec_end();    ftp->request_data_prot = 0;    ftp->buffer_size = 0;#endif    ftp->LIST_type = ltUnknown;    list_free(ftp->taglist);    ftp->taglist = list_new((listfunc)rfile_destroy);}void ftp_close(void){    ftp_trace("Closing down connection...\n");    auto_create_bookmark();    if(gvLoadTaglist != 0) {        save_taglist(0);    }    ftp_reset_vars();}void ftp_quit_all(void){    listitem *li;    /* nicely close all open connections */    for(li=gvFtpList->first; li; li=li->next) {        ftp_use((Ftp *)li->data);        ftp_quit();    }}#ifdef HAVE_POSIX_SIGSETJMPstatic sigjmp_buf open_timeout_jmp;#elsestatic jmp_buf open_timeout_jmp;#endifstatic RETSIGTYPE ftp_open_handler(int signum){    ftp_longjmp(open_timeout_jmp, 1);}int ftp_open_url(url_t *urlp, bool reset_vars){    bool use_proxy;    int i;    if(reset_vars)        ftp_reset_vars();    /* don't assume server is in ascii mode initially even if RFC says so */    ftp->prev_type = '?';#ifdef HAVE_POSIX_SIGSETJMP    if(sigsetjmp(open_timeout_jmp, 1))#else    if(setjmp(open_timeout_jmp))#endif    {        ftp_close();        ftp_err(_("Connection timeout after %u seconds\n"),                ftp->open_timeout);        return 1;    }    ftp_set_signal(SIGALRM, ftp_open_handler);    alarm(ftp->open_timeout);    use_proxy = (proxy_type(urlp) != 0);    ftp_err(_("Looking up %s... "),            use_proxy ? gvProxyUrl->hostname : urlp->hostname);    /* Set the default port (22) for SSH if no port is specified. We     * need to do this here, 'cause host_lookup() sets it to 21     * (default port for vanilla FTP)     */    if(urlp->protocol) {        if(strcmp(urlp->protocol, "sftp") == 0)            url_setprotocol(urlp, "ssh");        if(strcmp(urlp->protocol, "ssh") == 0 && urlp->port == -1)            urlp->port = 22; /* default SSH port */    }    ftp->host = host_create(use_proxy ? gvProxyUrl : urlp);    if(host_lookup(ftp->host) != 0) {        herror(ftp->host->hostname);        alarm(0);        ftp_set_signal(SIGALRM, SIG_IGN);        return -1;    }    urlp->port = ntohs(ftp->host->port);    fprintf(stderr, "\r               ");    i = strlen(use_proxy ? gvProxyUrl->hostname : urlp->hostname);    while(i--)        fprintf(stderr, " ");    fprintf(stderr, "\r");    ftp_trace("\n");    if(urlp->protocol && strcmp(urlp->protocol, "ssh") == 0) {        int ret = ssh_open_url(urlp);        alarm(0);        return ret;    }    if(urlp->protocol && strcmp(urlp->protocol, "ftp") != 0) {        ftp_err(_("Sorry, don't know how to handle your '%s' protocol\n"                  "trying 'ftp' instead...\n"),                urlp->protocol);        url_setprotocol(urlp, 0);    }    if(use_proxy) {        ftp_err(_("Connecting to proxy %s (%s) at port %d...\n"),                ftp->host->ohostname, ftp->host->ipnum,                urlp->port);    } else {        ftp_err(_("Connecting to %s (%s) at port %d...\n"),                ftp->host->ohostname, ftp->host->ipnum,                urlp->port);    }    ftp->ctrl = sock_create();    if(sock_connect_host(ftp->ctrl, ftp->host) == -1) {        alarm(0);        ftp_set_signal(SIGALRM, SIG_IGN);        return -1;    }    sock_lowdelay(ftp->ctrl);    /* read startup message from server */    ftp_set_tmp_verbosity(vbCommand);    ftp_read_reply();    if(ftp->fullcode == 120) {        ftp_set_tmp_verbosity(vbCommand);        ftp_read_reply();    }    alarm(0);    ftp_set_signal(SIGALRM, SIG_IGN);    if(!sock_connected(ftp->ctrl)) {        ftp_close();        return 1;    }    ftp->connected = (ftp->fullcode == 220);    if(ftp->connected) {        void (*tracefunq)(const char *fmt, ...);        unsigned char *a;        url_destroy(ftp->url);        ftp->url = url_clone(urlp);        tracefunq = (ftp->verbosity == vbDebug ? ftp_err : ftp_trace);        a = (unsigned char *)&ftp->ctrl->remote_addr.sin_addr;        tracefunq("remote address: %d.%d.%d.%d\n", a[0], a[1], a[2], a[3]);        a = (unsigned char *)&ftp->ctrl->local_addr.sin_addr;        tracefunq("local address: %d.%d.%d.%d\n", a[0], a[1], a[2], a[3]);        return 0;    } else {        ftp_close();        return 1;    }}int ftp_open(const char *host){    url_t *url;    url = url_init(host);    return ftp_open_url(ftp->url, true);}int ftp_reopen(void){    if(ftp && ftp->url) {        url_t *u = url_clone(ftp->url);        int r;        url_setdirectory(u, ftp->curdir);        r = ftp_open_url(u, false);        if(r == 0) {            r = ftp_login(u->username, gvAnonPasswd);        } else            ftp_close();        url_destroy(u);        return r;    }    return -1;}/* reads one line from server into ftp->reply * returns 0 on success or -1 on failure */static int ftp_gets(void){    int c, i=0;    ftp->reply[0] = 0;    if(!sock_connected(ftp->ctrl)) {        ftp_err(_("No control connection\n"));        return -1;    }    while(true) {        c = sock_get(ftp->ctrl);        if(c == EOF) {            ftp_err(_("Server has closed control connection\n"));            ftp_close();            return -1;        }        else if(c == 255/*IAC*/) {   /* handle telnet commands */            switch(c = sock_get(ftp->ctrl)) {              case 251/*WILL*/:              case 252/*WONT*/:                c = sock_get(ftp->ctrl);                sock_printf(ftp->ctrl, "%c%c%c", 255/*IAC*/, 254/*DONT*/, c);                sock_flush(ftp->ctrl);                break;              case 253/*DO*/:              case 254/*DONT*/:                c = sock_get(ftp->ctrl);                sock_printf(ftp->ctrl, "%c%c%c", 255/*IAC*/, 252/*WONT*/, c);                sock_flush(ftp->ctrl);                break;              default:                break;            }            continue;        }        else if(c == '\r') {            c = sock_get(ftp->ctrl);            if(c == 0)                c = '\r';            else if(c == '\n') {                ftp->reply[i++] = (char)c;                break;            } else if(c == EOF)                /* do nothing */ ;            else { /* telnet protocol violation, hmpf... */                sock_unget(ftp->ctrl, c);                continue;            }        }        else if(c == '\n')            break;        if(i < MAXREPLY)            ftp->reply[i++] = (char)c;    }    if(i >= MAXREPLY) {        ftp_err(_("Reply too long (truncated)\n"));        i = MAXREPLY;    }    ftp->reply[i] = '\0';    ftp->fullcode = atoi(ftp->reply);#ifdef SECFTP    {        int r = 0;        switch(ftp->fullcode) { /* handle protected responses 6xx */        case 631:            r = sec_read_msg(ftp->reply, prot_safe);            break;        case 632:            r = sec_read_msg(ftp->reply, prot_private);            break;        case 633:            r = sec_read_msg(ftp->reply, prot_confidential);            break;        }        if(r == -1) {            ftp->fullcode = 0;            ftp->code = vbNone;            return 0;        } else            ftp->fullcode = atoi(ftp->reply);    }#endif    strip_trailing_chars(ftp->reply, "\n\r");    ftp->code = ftp->fullcode / 100;    return ftp->fullcode;}const char *ftp_getreply(bool withcode){    char *r = ftp->reply;    if(ftp->ssh_pid)        return fx2txt(ftp->ssh_last_status);    if(withcode)        return r;    if(isdigit((int)r[0]))        r += 3;    if(r[0] == '-' || r[0] == ' ')        r++;    return r;}static void ftp_print_reply(void){    verbose_t v = ftp_get_verbosity();    ftp_trace("<-- [%s] %s\n",              ftp->url ? ftp->url->hostname : ftp->host->hostname,              ftp_getreply(true));    if(v >= vbCommand || (ftp->code >= ctTransient && v == vbError)) {        if(v == vbDebug)            fprintf(stderr, "<-- [%s] %s\n",                    ftp->url ? ftp->url->hostname : ftp->host->hostname,                    ftp_getreply(true));        else            fprintf(stderr, "%s\n", ftp_getreply(false));    }}static RETSIGTYPE reply_ALRM_handler(int signum){    ftp_err(_("Tired of waiting for reply, timeout after %u seconds\n"),            ftp->reply_timeout);    ftp_close();    if(gvJmpBufSet) {        ftp_trace("jumping to gvRestartJmp\n");        ftp_longjmp(gvRestartJmp, 1);    } else        exit_yafc();}/* reads reply * returns 0 on success or -1 on error */int ftp_read_reply(void){    char tmp[5]="xxx ";    int r;    ftp_set_signal(SIGALRM, reply_ALRM_handler);    if(ftp->reply_timeout)        alarm(ftp->reply_timeout);    clearerr(ftp->ctrl->sin);    r = ftp_gets();    if(!sock_connected(ftp->ctrl)) {        alarm(0);        ftp_set_signal(SIGALRM, SIG_DFL);        return -1;    }    if(r == -1) {        alarm(0);        ftp_set_signal(SIGALRM, SIG_DFL);        ftp_trace("ftp_gets returned -1\n");        return -1;    }    ftp_print_reply();    if(ftp->reply[3] == '-') {  /* multiline response */        strncpy(tmp, ftp->reply, 3);        do {            if(ftp_gets() == -1)                break;            ftp_print_reply();        } while(strncmp(tmp, ftp->reply, 4) != 0);    }    ftp->tmp_verbosity = vbUnset;    alarm(0);    ftp_set_signal(SIGALRM, SIG_DFL);    return r;}static void ftp_print_cmd(const char *cmd, va_list ap){    if(ftp_get_verbosity() == vbDebug) {        ftp_err("--> [%s] ", ftp->url->hostname);        if(strncmp(cmd, "PASS", 4) == 0)            ftp_err("PASS ********");        else {            vfprintf(stderr, cmd, ap);            ftp_vtrace(cmd, ap);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -