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

📄 pscp.c

📁 putty
💻 C
📖 第 1 页 / 共 4 页
字号:
	    sfree(filename);
	}
    }
    close_directory(dir);

    (void) scp_send_enddir();

    scp_restore_remotepath(save_target);
}

/*
 * Execute the sink part of the SCP protocol.
 */
static void sink(char *targ, char *src)
{
    char *destfname;
    int targisdir = 0;
    int exists;
    int attr;
    WFile *f;
    uint64 received;
    int wrerror = 0;
    uint64 stat_bytes;
    time_t stat_starttime, stat_lasttime;
    char *stat_name;

    attr = file_type(targ);
    if (attr == FILE_TYPE_DIRECTORY)
	targisdir = 1;

    if (targetshouldbedirectory && !targisdir)
	bump("%s: Not a directory", targ);

    scp_sink_init();
    while (1) {
	struct scp_sink_action act;
	if (scp_get_sink_action(&act))
	    return;

	if (act.action == SCP_SINK_ENDDIR)
	    return;

	if (act.action == SCP_SINK_RETRY)
	    continue;

	if (targisdir) {
	    /*
	     * Prevent the remote side from maliciously writing to
	     * files outside the target area by sending a filename
	     * containing `../'. In fact, it shouldn't be sending
	     * filenames with any slashes or colons in at all; so
	     * we'll find the last slash, backslash or colon in the
	     * filename and use only the part after that. (And
	     * warn!)
	     * 
	     * In addition, we also ensure here that if we're
	     * copying a single file and the target is a directory
	     * (common usage: `pscp host:filename .') the remote
	     * can't send us a _different_ file name. We can
	     * distinguish this case because `src' will be non-NULL
	     * and the last component of that will fail to match
	     * (the last component of) the name sent.
	     * 
	     * Well, not always; if `src' is a wildcard, we do
	     * expect to get back filenames that don't correspond
	     * exactly to it. Ideally in this case, we would like
	     * to ensure that the returned filename actually
	     * matches the wildcard pattern - but one of SCP's
	     * protocol infelicities is that wildcard matching is
	     * done at the server end _by the server's rules_ and
	     * so in general this is infeasible. Hence, we only
	     * accept filenames that don't correspond to `src' if
	     * unsafe mode is enabled or we are using SFTP (which
	     * resolves remote wildcards on the client side and can
	     * be trusted).
	     */
	    char *striptarget, *stripsrc;

	    striptarget = stripslashes(act.name, 1);
	    if (striptarget != act.name) {
		tell_user(stderr, "warning: remote host sent a compound"
			  " pathname '%s'", act.name);
		tell_user(stderr, "         renaming local file to '%s'",
                          striptarget);
	    }

	    /*
	     * Also check to see if the target filename is '.' or
	     * '..', or indeed '...' and so on because Windows
	     * appears to interpret those like '..'.
	     */
	    if (is_dots(striptarget)) {
		bump("security violation: remote host attempted to write to"
		     " a '.' or '..' path!");
	    }

	    if (src) {
		stripsrc = stripslashes(src, 1);
		if (strcmp(striptarget, stripsrc) &&
		    !using_sftp && !scp_unsafe_mode) {
		    tell_user(stderr, "warning: remote host tried to write "
			      "to a file called '%s'", striptarget);
		    tell_user(stderr, "         when we requested a file "
			      "called '%s'.", stripsrc);
		    tell_user(stderr, "         If this is a wildcard, "
			      "consider upgrading to SSH-2 or using");
		    tell_user(stderr, "         the '-unsafe' option. Renaming"
			      " of this file has been disallowed.");
		    /* Override the name the server provided with our own. */
		    striptarget = stripsrc;
		}
	    }

	    if (targ[0] != '\0')
		destfname = dir_file_cat(targ, striptarget);
	    else
		destfname = dupstr(striptarget);
	} else {
	    /*
	     * In this branch of the if, the target area is a
	     * single file with an explicitly specified name in any
	     * case, so there's no danger.
	     */
	    destfname = dupstr(targ);
	}
	attr = file_type(destfname);
	exists = (attr != FILE_TYPE_NONEXISTENT);

	if (act.action == SCP_SINK_DIR) {
	    if (exists && attr != FILE_TYPE_DIRECTORY) {
		run_err("%s: Not a directory", destfname);
		continue;
	    }
	    if (!exists) {
		if (!create_directory(destfname)) {
		    run_err("%s: Cannot create directory", destfname);
		    continue;
		}
	    }
	    sink(destfname, NULL);
	    /* can we set the timestamp for directories ? */
	    continue;
	}

	f = open_new_file(destfname);
	if (f == NULL) {
	    run_err("%s: Cannot create file", destfname);
	    continue;
	}

	if (scp_accept_filexfer())
	    return;

	stat_bytes = uint64_make(0, 0);
	stat_starttime = time(NULL);
	stat_lasttime = 0;
	stat_name = stripslashes(destfname, 1);

	received = uint64_make(0, 0);
	while (uint64_compare(received,act.size) < 0) {
	    char transbuf[32768];
	    uint64 blksize;
	    int read;
	    blksize = uint64_make(0, 32768);
	    if (uint64_compare(blksize,uint64_subtract(act.size,received)) > 0)
	      blksize = uint64_subtract(act.size,received);
	    read = scp_recv_filedata(transbuf, (int)blksize.lo);
	    if (read <= 0)
		bump("Lost connection");
	    if (wrerror)
		continue;
	    if (write_to_file(f, transbuf, read) != (int)read) {
		wrerror = 1;
		/* FIXME: in sftp we can actually abort the transfer */
		if (statistics)
		    printf("\r%-25.25s | %50s\n",
			   stat_name,
			   "Write error.. waiting for end of file");
		continue;
	    }
	    if (statistics) {
		stat_bytes = uint64_add32(stat_bytes,read);
		if (time(NULL) > stat_lasttime ||
		    uint64_compare(uint64_add32(received, read), act.size) == 0) {
		    stat_lasttime = time(NULL);
		    print_stats(stat_name, act.size, stat_bytes,
				stat_starttime, stat_lasttime);
		}
	    }
	    received = uint64_add32(received, read);
	}
	if (act.settime) {
	    set_file_times(f, act.mtime, act.atime);
	}

	close_wfile(f);
	if (wrerror) {
	    run_err("%s: Write error", destfname);
	    continue;
	}
	(void) scp_finish_filerecv();
	sfree(destfname);
	sfree(act.buf);
    }
}

/*
 * We will copy local files to a remote server.
 */
static void toremote(int argc, char *argv[])
{
    char *src, *targ, *host, *user;
    char *cmd;
    int i, wc_type;

    targ = argv[argc - 1];

    /* Separate host from filename */
    host = targ;
    targ = colon(targ);
    if (targ == NULL)
	bump("targ == NULL in toremote()");
    *targ++ = '\0';
    if (*targ == '\0')
	targ = ".";
    /* Substitute "." for empty target */

    /* Separate host and username */
    user = host;
    host = strrchr(host, '@');
    if (host == NULL) {
	host = user;
	user = NULL;
    } else {
	*host++ = '\0';
	if (*user == '\0')
	    user = NULL;
    }

    if (argc == 2) {
	if (colon(argv[0]) != NULL)
	    bump("%s: Remote to remote not supported", argv[0]);

	wc_type = test_wildcard(argv[0], 1);
	if (wc_type == WCTYPE_NONEXISTENT)
	    bump("%s: No such file or directory\n", argv[0]);
	else if (wc_type == WCTYPE_WILDCARD)
	    targetshouldbedirectory = 1;
    }

    cmd = dupprintf("scp%s%s%s%s -t %s",
		    verbose ? " -v" : "",
		    recursive ? " -r" : "",
		    preserve ? " -p" : "",
		    targetshouldbedirectory ? " -d" : "", targ);
    do_cmd(host, user, cmd);
    sfree(cmd);

    if (scp_source_setup(targ, targetshouldbedirectory))
	return;

    for (i = 0; i < argc - 1; i++) {
	src = argv[i];
	if (colon(src) != NULL) {
	    tell_user(stderr, "%s: Remote to remote not supported\n", src);
	    errs++;
	    continue;
	}

	wc_type = test_wildcard(src, 1);
	if (wc_type == WCTYPE_NONEXISTENT) {
	    run_err("%s: No such file or directory", src);
	    continue;
	} else if (wc_type == WCTYPE_FILENAME) {
	    source(src);
	    continue;
	} else {
	    WildcardMatcher *wc;
	    char *filename;

	    wc = begin_wildcard_matching(src);
	    if (wc == NULL) {
		run_err("%s: No such file or directory", src);
		continue;
	    }

	    while ((filename = wildcard_get_filename(wc)) != NULL) {
		source(filename);
		sfree(filename);
	    }

	    finish_wildcard_matching(wc);
	}
    }
}

/*
 *  We will copy files from a remote server to the local machine.
 */
static void tolocal(int argc, char *argv[])
{
    char *src, *targ, *host, *user;
    char *cmd;

    if (argc != 2)
	bump("More than one remote source not supported");

    src = argv[0];
    targ = argv[1];

    /* Separate host from filename */
    host = src;
    src = colon(src);
    if (src == NULL)
	bump("Local to local copy not supported");
    *src++ = '\0';
    if (*src == '\0')
	src = ".";
    /* Substitute "." for empty filename */

    /* Separate username and hostname */
    user = host;
    host = strrchr(host, '@');
    if (host == NULL) {
	host = user;
	user = NULL;
    } else {
	*host++ = '\0';
	if (*user == '\0')
	    user = NULL;
    }

    cmd = dupprintf("scp%s%s%s%s -f %s",
		    verbose ? " -v" : "",
		    recursive ? " -r" : "",
		    preserve ? " -p" : "",
		    targetshouldbedirectory ? " -d" : "", src);
    do_cmd(host, user, cmd);
    sfree(cmd);

    if (scp_sink_setup(src, preserve, recursive))
	return;

    sink(targ, src);
}

/*
 *  We will issue a list command to get a remote directory.
 */
static void get_dir_list(int argc, char *argv[])
{
    char *src, *host, *user;
    char *cmd, *p, *q;
    char c;

    src = argv[0];

    /* Separate host from filename */
    host = src;
    src = colon(src);
    if (src == NULL)
	bump("Local to local copy not supported");
    *src++ = '\0';
    if (*src == '\0')
	src = ".";
    /* Substitute "." for empty filename */

    /* Separate username and hostname */
    user = host;
    host = strrchr(host, '@');
    if (host == NULL) {
	host = user;
	user = NULL;
    } else {
	*host++ = '\0';
	if (*user == '\0')
	    user = NULL;
    }

    cmd = snewn(4 * strlen(src) + 100, char);
    strcpy(cmd, "ls -la '");
    p = cmd + strlen(cmd);
    for (q = src; *q; q++) {
	if (*q == '\'') {
	    *p++ = '\'';
	    *p++ = '\\';
	    *p++ = '\'';
	    *p++ = '\'';
	} else {
	    *p++ = *q;
	}
    }
    *p++ = '\'';
    *p = '\0';

    do_cmd(host, user, cmd);
    sfree(cmd);

    if (using_sftp) {
	scp_sftp_listdir(src);
    } else {
	while (ssh_scp_recv((unsigned char *) &c, 1) > 0)
	    tell_char(stdout, c);
    }
}

/*
 *  Short description of parameters.
 */
static void usage(void)
{
    printf("PuTTY Secure Copy client\n");
    printf("%s\n", ver);
    printf("Usage: pscp [options] [user@]host:source target\n");
    printf
	("       pscp [options] source [source...] [user@]host:target\n");
    printf("       pscp [options] -ls [user@]host:filespec\n");
    printf("Options:\n");
    printf("  -V        print version information and exit\n");
    printf("  -pgpfp    print PGP key fingerprints and exit\n");
    printf("  -p        preserve file attributes\n");
    printf("  -q        quiet, don't show statistics\n");
    printf("  -r        copy directories recursively\n");
    printf("  -v        show verbose messages\n");
    printf("  -load sessname  Load settings from saved session\n");
    printf("  -P port   connect to specified port\n");
    printf("  -l user   connect with specified username\n");
    printf("  -pw passw login with specified password\n");
    printf("  -1 -2     force use of particular SSH protocol version\n");
    printf("  -4 -6     force use of IPv4 or IPv6\n");
    printf("  -C        enable compression\n");
    printf("  -i key    private key file for authentication\n");
    printf("  -noagent  disable use of Pageant\n");
    printf("  -agent    enable use of Pageant\n");
    printf("  -batch    disable all interactive prompts\n");
    printf("  -unsafe   allow server-side wildcards (DANGEROUS)\n");
    printf("  -sftp     force use of SFTP protocol\n");
    printf("  -scp      force use of SCP protocol\n");
#if 0
    /*
     * -gui is an internal option, used by GUI front ends to get
     * pscp to pass progress reports back to them. It's not an
     * ordinary user-accessible option, so it shouldn't be part of
     * the command-line help. The only people who need to know
     * about it are programmers, and they can read the source.
     */
    printf
	("  -gui hWnd GUI mode with the windows handle for receiving messages\n");
#endif
    cleanup_exit(1);
}

void version(void)
{
    printf("pscp: %s\n", ver);
    cleanup_exit(1);
}

void cmdline_error(char *p, ...)
{
    va_list ap;
    fprintf(stderr, "pscp: ");
    va_start(ap, p);
    vfprintf(stderr, p, ap);
    va_end(ap);
    fprintf(stderr, "\n      try typing just \"pscp\" for help\n");
    exit(1);
}

/*
 * Main program. (Called `psftp_main' because it gets called from
 * *sftp.c; bit silly, I know, but it had to be called _something_.)
 */
int psftp_main(int argc, char *argv[])
{
    int i;

    default_protocol = PROT_TELNET;

    flags = FLAG_STDERR
#ifdef FLAG_SYNCAGENT
	| FLAG_SYNCAGENT
#endif
	;
    cmdline_tooltype = TOOLTYPE_FILETRANSFER;
    sk_init();

    /* Load Default Settings before doing anything else. */
    do_defaults(NULL, &cfg);
    loaded_session = FALSE;

    for (i = 1; i < argc; i++) {
	int ret;
	if (argv[i][0] != '-')
	    break;
	ret = cmdline_process_param(argv[i], i+1<argc?argv[i+1]:NULL, 1, &cfg);
	if (ret == -2) {
	    cmdline_error("option \"%s\" requires an argument", argv[i]);
	} else if (ret == 2) {
	    i++;	       /* skip next argument */
	} else if (ret == 1) {
	    /* We have our own verbosity in addition to `flags'. */
	    if (flags & FLAG_VERBOSE)
		verbose = 1;
        } else if (strcmp(argv[i], "-pgpfp") == 0) {
            pgp_fingerprints();
            return 1;
	} else if (strcmp(argv[i], "-r") == 0) {
	    recursive = 1;
	} else if (strcmp(argv[i], "-p") == 0) {
	    preserve = 1;
	} else if (strcmp(argv[i], "-q") == 0) {
	    statistics = 0;
	} else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0) {
	    usage();
	} else if (strcmp(argv[i], "-V") == 0) {
            version();
        } else if (strcmp(argv[i], "-ls") == 0) {
	    list = 1;
	} else if (strcmp(argv[i], "-batch") == 0) {
	    console_batch_mode = 1;
	} else if (strcmp(argv[i], "-unsafe") == 0) {
	    scp_unsafe_mode = 1;
	} else if (strcmp(argv[i], "-sftp") == 0) {
	    try_scp = 0; try_sftp = 1;
	} else if (strcmp(argv[i], "-scp") == 0) {
	    try_scp = 1; try_sftp = 0;
	} else if (strcmp(argv[i], "--") == 0) {
	    i++;
	    break;
	} else {
	    cmdline_error("unknown option \"%s\"", argv[i]);
	}
    }
    argc -= i;
    argv += i;
    back = NULL;

    if (list) {
	if (argc != 1)
	    usage();
	get_dir_list(argc, argv);

    } else {

	if (argc < 2)
	    usage();
	if (argc > 2)
	    targetshouldbedirectory = 1;

	if (colon(argv[argc - 1]) != NULL)
	    toremote(argc, argv);
	else
	    tolocal(argc, argv);
    }

    if (back != NULL && back->connected(backhandle)) {
	char ch;
	back->special(backhandle, TS_EOF);
	ssh_scp_recv((unsigned char *) &ch, 1);
    }
    random_save_seed();

    cmdline_cleanup();
    console_provide_logctx(NULL);
    back->free(backhandle);
    backhandle = NULL;
    back = NULL;
    sk_cleanup();
    return (errs == 0 ? 0 : 1);
}

/* end */

⌨️ 快捷键说明

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