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

📄 scp.c

📁 大名鼎鼎的远程登录软件putty的Symbian版源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * scp.c  -  Scp (Secure Copy) client for PuTTY. * Joris van Rantwijk, Simon Tatham * * This is mainly based on ssh-1.2.26/scp.c by Timo Rinne & Tatu Ylonen. * They, in turn, used stuff from BSD rcp. *  * (SGT, 2001-09-10: Joris van Rantwijk assures me that although * this file as originally submitted was inspired by, and * _structurally_ based on, ssh-1.2.26's scp.c, there wasn't any * actual code duplicated, so the above comment shouldn't give rise * to licensing issues.) */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <limits.h>#include <time.h>#include <assert.h>#define PUTTY_DO_GLOBALS#include "putty.h"#include "psftp.h"#include "ssh.h"#include "sftp.h"#include "storage.h"static int list = 0;static int verbose = 0;static int recursive = 0;static int preserve = 0;static int targetshouldbedirectory = 0;static int statistics = 1;static int prev_stats_len = 0;static int scp_unsafe_mode = 0;static int errs = 0;static int gui_mode = 0;static int try_scp = 1;static int try_sftp = 1;static int main_cmd_is_sftp = 0;static int fallback_cmd_is_sftp = 0;static int using_sftp = 0;static const Backend *back;static void *backhandle;static Config cfg;static void source(char *src);static void rsource(char *src);static void sink(char *targ, char *src);/* * The maximum amount of queued data we accept before we stop and * wait for the server to process some. */#define MAX_SCP_BUFSIZE 16384void ldisc_send(void *handle, char *buf, int len, int interactive){    /*     * This is only here because of the calls to ldisc_send(NULL,     * 0) in ssh.c. Nothing in PSCP actually needs to use the ldisc     * as an ldisc. So if we get called with any real data, I want     * to know about it.     */    assert(len == 0);}static void tell_char(FILE * stream, char c){    if (!gui_mode)	fputc(c, stream);    else	gui_send_char(stream == stderr, c);}static void tell_str(FILE * stream, char *str){    unsigned int i;    for (i = 0; i < strlen(str); ++i)	tell_char(stream, str[i]);}static void tell_user(FILE * stream, char *fmt, ...){    char *str, *str2;    va_list ap;    va_start(ap, fmt);    str = dupvprintf(fmt, ap);    va_end(ap);    str2 = dupcat(str, "\n", NULL);    sfree(str);    tell_str(stream, str2);    sfree(str2);}/* *  Print an error message and perform a fatal exit. */void fatalbox(char *fmt, ...){    char *str, *str2;    va_list ap;    va_start(ap, fmt);    str = dupvprintf(fmt, ap);    str2 = dupcat("Fatal: ", str, "\n", NULL);    sfree(str);    va_end(ap);    tell_str(stderr, str2);    sfree(str2);    errs++;    if (gui_mode)	gui_send_errcount(list, errs);    cleanup_exit(1);}void modalfatalbox(char *fmt, ...){    char *str, *str2;    va_list ap;    va_start(ap, fmt);    str = dupvprintf(fmt, ap);    str2 = dupcat("Fatal: ", str, "\n", NULL);    sfree(str);    va_end(ap);    tell_str(stderr, str2);    sfree(str2);    errs++;    if (gui_mode)	gui_send_errcount(list, errs);    cleanup_exit(1);}void connection_fatal(void *frontend, char *fmt, ...){    char *str, *str2;    va_list ap;    va_start(ap, fmt);    str = dupvprintf(fmt, ap);    str2 = dupcat("Fatal: ", str, "\n", NULL);    sfree(str);    va_end(ap);    tell_str(stderr, str2);    sfree(str2);    errs++;    if (gui_mode)	gui_send_errcount(list, errs);    cleanup_exit(1);}/* * In pscp, all agent requests should be synchronous, so this is a * never-called stub. */void agent_schedule_callback(void (*callback)(void *, void *, int),			     void *callback_ctx, void *data, int len){    assert(!"We shouldn't be here");}/* * Receive a block of data from the SSH link. Block until all data * is available. * * To do this, we repeatedly call the SSH protocol module, with our * own trap in from_backend() to catch the data that comes back. We * do this until we have enough data. */static unsigned char *outptr;	       /* where to put the data */static unsigned outlen;		       /* how much data required */static unsigned char *pending = NULL;  /* any spare data */static unsigned pendlen = 0, pendsize = 0;	/* length and phys. size of buffer */int from_backend(void *frontend, int is_stderr, const char *data, int datalen){    unsigned char *p = (unsigned char *) data;    unsigned len = (unsigned) datalen;    /*     * stderr data is just spouted to local stderr and otherwise     * ignored.     */    if (is_stderr) {	if (len > 0)	    fwrite(data, 1, len, stderr);	return 0;    }    /*     * If this is before the real session begins, just return.     */    if (!outptr)	return 0;    if ((outlen > 0) && (len > 0)) {	unsigned used = outlen;	if (used > len)	    used = len;	memcpy(outptr, p, used);	outptr += used;	outlen -= used;	p += used;	len -= used;    }    if (len > 0) {	if (pendsize < pendlen + len) {	    pendsize = pendlen + len + 4096;	    pending = sresize(pending, pendsize, unsigned char);	    if (!pending)		fatalbox("Out of memory");	}	memcpy(pending + pendlen, p, len);	pendlen += len;    }    return 0;}static int ssh_scp_recv(unsigned char *buf, int len){    outptr = buf;    outlen = len;    /*     * See if the pending-input block contains some of what we     * need.     */    if (pendlen > 0) {	unsigned pendused = pendlen;	if (pendused > outlen)	    pendused = outlen;	memcpy(outptr, pending, pendused);	memmove(pending, pending + pendused, pendlen - pendused);	outptr += pendused;	outlen -= pendused;	pendlen -= pendused;	if (pendlen == 0) {	    pendsize = 0;	    sfree(pending);	    pending = NULL;	}	if (outlen == 0)	    return len;    }    while (outlen > 0) {	if (ssh_sftp_loop_iteration() < 0)	    return 0;		       /* doom */    }    return len;}/* * Loop through the ssh connection and authentication process. */static void ssh_scp_init(void){    while (!back->sendok(backhandle)) {	if (ssh_sftp_loop_iteration() < 0)	    return;		       /* doom */    }    /* Work out which backend we ended up using. */    if (!ssh_fallback_cmd(backhandle))	using_sftp = main_cmd_is_sftp;    else	using_sftp = fallback_cmd_is_sftp;    if (verbose) {	if (using_sftp)	    tell_user(stderr, "Using SFTP");	else	    tell_user(stderr, "Using SCP1");    }}/* *  Print an error message and exit after closing the SSH link. */static void bump(char *fmt, ...){    char *str, *str2;    va_list ap;    va_start(ap, fmt);    str = dupvprintf(fmt, ap);    va_end(ap);    str2 = dupcat(str, "\n", NULL);    sfree(str);    tell_str(stderr, str2);    sfree(str2);    errs++;    if (back != NULL && back->socket(backhandle) != NULL) {	char ch;	back->special(backhandle, TS_EOF);	ssh_scp_recv((unsigned char *) &ch, 1);    }    if (gui_mode)	gui_send_errcount(list, errs);    cleanup_exit(1);}/* *  Open an SSH connection to user@host and execute cmd. */static void do_cmd(char *host, char *user, char *cmd){    const char *err;    char *realhost;    void *logctx;    if (host == NULL || host[0] == '\0')	bump("Empty host name");    /*     * If we haven't loaded session details already (e.g., from -load),     * try looking for a session called "host".     */    if (!loaded_session) {	/* Try to load settings for `host' into a temporary config */	Config cfg2;	cfg2.host[0] = '\0';	do_defaults(host, &cfg2);	if (cfg2.host[0] != '\0') {	    /* Settings present and include hostname */	    /* Re-load data into the real config. */	    do_defaults(host, &cfg);	} else {	    /* Session doesn't exist or mention a hostname. */	    /* Use `host' as a bare hostname. */	    strncpy(cfg.host, host, sizeof(cfg.host) - 1);	    cfg.host[sizeof(cfg.host) - 1] = '\0';	}    } else {	/* Patch in hostname `host' to session details. */	strncpy(cfg.host, host, sizeof(cfg.host) - 1);	cfg.host[sizeof(cfg.host) - 1] = '\0';    }    /*     * Force use of SSH. (If they got the protocol wrong we assume the     * port is useless too.)     */    if (cfg.protocol != PROT_SSH) {        cfg.protocol = PROT_SSH;        cfg.port = 22;    }    /*     * Enact command-line overrides.     */    cmdline_run_saved(&cfg);    /*     * Trim leading whitespace off the hostname if it's there.     */    {	int space = strspn(cfg.host, " \t");	memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space);    }    /* See if host is of the form user@host */    if (cfg.host[0] != '\0') {	char *atsign = strrchr(cfg.host, '@');	/* Make sure we're not overflowing the user field */	if (atsign) {	    if (atsign - cfg.host < sizeof cfg.username) {		strncpy(cfg.username, cfg.host, atsign - cfg.host);		cfg.username[atsign - cfg.host] = '\0';	    }	    memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1));	}    }    /*     * Trim a colon suffix off the hostname if it's there.     */    cfg.host[strcspn(cfg.host, ":")] = '\0';    /*     * Remove any remaining whitespace from the hostname.     */    {	int p1 = 0, p2 = 0;	while (cfg.host[p2] != '\0') {	    if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') {		cfg.host[p1] = cfg.host[p2];		p1++;	    }	    p2++;	}	cfg.host[p1] = '\0';    }    /* Set username */    if (user != NULL && user[0] != '\0') {	strncpy(cfg.username, user, sizeof(cfg.username) - 1);	cfg.username[sizeof(cfg.username) - 1] = '\0';    } else if (cfg.username[0] == '\0') {	user = get_username();	if (!user)	    bump("Empty user name");	else {	    if (verbose)		tell_user(stderr, "Guessing user name: %s", user);	    strncpy(cfg.username, user, sizeof(cfg.username) - 1);	    cfg.username[sizeof(cfg.username) - 1] = '\0';	    sfree(user);	}    }    /*     * Disable scary things which shouldn't be enabled for simple     * things like SCP and SFTP: agent forwarding, port forwarding,     * X forwarding.     */    cfg.x11_forward = 0;    cfg.agentfwd = 0;    cfg.portfwd[0] = cfg.portfwd[1] = '\0';    /*     * Set up main and possibly fallback command depending on     * options specified by user.     * Attempt to start the SFTP subsystem as a first choice,     * falling back to the provided scp command if that fails.     */    cfg.remote_cmd_ptr2 = NULL;    if (try_sftp) {	/* First choice is SFTP subsystem. */	main_cmd_is_sftp = 1;	strcpy(cfg.remote_cmd, "sftp");	cfg.ssh_subsys = TRUE;	if (try_scp) {	    /* Fallback is to use the provided scp command. */	    fallback_cmd_is_sftp = 0;	    cfg.remote_cmd_ptr2 = cmd;	    cfg.ssh_subsys2 = FALSE;	} else {	    /* Since we're not going to try SCP, we may as well try	     * harder to find an SFTP server, since in the current	     * implementation we have a spare slot. */	    fallback_cmd_is_sftp = 1;	    /* see psftp.c for full explanation of this kludge */	    cfg.remote_cmd_ptr2 = 		"test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n"		"test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n"		"exec sftp-server";	    cfg.ssh_subsys2 = FALSE;	}    } else {	/* Don't try SFTP at all; just try the scp command. */	main_cmd_is_sftp = 0;	cfg.remote_cmd_ptr = cmd;	cfg.ssh_subsys = FALSE;    }    cfg.nopty = TRUE;    back = &ssh_backend;    err = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, 		     0, cfg.tcp_keepalives);    if (err != NULL)	bump("ssh_init: %s", err);    logctx = log_init(NULL, &cfg);    back->provide_logctx(backhandle, logctx);    console_provide_logctx(logctx);    ssh_scp_init();    if (verbose && realhost != NULL)	tell_user(stderr, "Connected to %s\n", realhost);    sfree(realhost);}/* *  Update statistic information about current file. */static void print_stats(char *name, unsigned long size, unsigned long done,			time_t start, time_t now){    float ratebs;    unsigned long eta;    char *etastr;    int pct;    int len;    int elap;    elap = (unsigned long) difftime(now, start);    if (now > start)	ratebs = (float) done / elap;    else	ratebs = (float) done;    if (ratebs < 1.0)	eta = size - done;    else	eta = (unsigned long) ((size - done) / ratebs);    etastr = dupprintf("%02ld:%02ld:%02ld",		       eta / 3600, (eta % 3600) / 60, eta % 60);    pct = (int) (100 * (done * 1.0 / size));    if (gui_mode) {	gui_update_stats(name, size, pct, elap, done, eta,			 (unsigned long) ratebs);    } else {	len = printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%",		     name, done / 1024, ratebs / 1024.0, etastr, pct);	if (len < prev_stats_len)	    printf("%*s", prev_stats_len - len, "");	prev_stats_len = len;	if (done == size)	    printf("\n");	fflush(stdout);    }    free(etastr);}/* *  Find a colon in str and return a pointer to the colon. *  This is used to separate hostname from filename. */static char *colon(char *str){    /* We ignore a leading colon, since the hostname cannot be       empty. We also ignore a colon as second character because       of filenames like f:myfile.txt. */    if (str[0] == '\0' || str[0] == ':' || str[1] == ':')	return (NULL);    while (*str != '\0' && *str != ':' && *str != '/' && *str != '\\')	str++;    if (*str == ':')	return (str);    else	return (NULL);}/* * Return a pointer to the portion of str that comes after the last * slash (or backslash or colon, if `local' is TRUE). */static char *stripslashes(char *str, int local){    char *p;    if (local) {        p = strchr(str, ':');        if (p) str = p+1;    }    p = strrchr(str, '/');    if (p) str = p+1;    if (local) {	p = strrchr(str, '\\');	if (p) str = p+1;

⌨️ 快捷键说明

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