📄 pscp.c
字号:
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 + -