2 * scp.c - Scp (Secure Copy) client for PuTTY.
3 * Joris van Rantwijk, Simon Tatham
5 * This is mainly based on ssh-1.2.26/scp.c by Timo Rinne & Tatu Ylonen.
6 * They, in turn, used stuff from BSD rcp.
8 * (SGT, 2001-09-10: Joris van Rantwijk assures me that although
9 * this file as originally submitted was inspired by, and
10 * _structurally_ based on, ssh-1.2.26's scp.c, there wasn't any
11 * actual code duplicated, so the above comment shouldn't give rise
12 * to licensing issues.)
30 #define PUTTY_DO_GLOBALS
37 #define TIME_POSIX_TO_WIN(t, ft) (*(LONGLONG*)&(ft) = \
38 ((LONGLONG) (t) + (LONGLONG) 11644473600) * (LONGLONG) 10000000)
39 #define TIME_WIN_TO_POSIX(ft, t) ((t) = (unsigned long) \
40 ((*(LONGLONG*)&(ft)) / (LONGLONG) 10000000 - (LONGLONG) 11644473600))
42 /* GUI Adaptation - Sept 2000 */
43 #define WM_APP_BASE 0x8000
44 #define WM_STD_OUT_CHAR ( WM_APP_BASE+400 )
45 #define WM_STD_ERR_CHAR ( WM_APP_BASE+401 )
46 #define WM_STATS_CHAR ( WM_APP_BASE+402 )
47 #define WM_STATS_SIZE ( WM_APP_BASE+403 )
48 #define WM_STATS_PERCENT ( WM_APP_BASE+404 )
49 #define WM_STATS_ELAPSED ( WM_APP_BASE+405 )
50 #define WM_RET_ERR_CNT ( WM_APP_BASE+406 )
51 #define WM_LS_RET_ERR_CNT ( WM_APP_BASE+407 )
52 #define WM_STATS_DONE ( WM_APP_BASE+408 )
53 #define WM_STATS_ETA ( WM_APP_BASE+409 )
54 #define WM_STATS_RATEBS ( WM_APP_BASE+410 )
57 static int verbose = 0;
58 static int recursive = 0;
59 static int preserve = 0;
60 static int targetshouldbedirectory = 0;
61 static int statistics = 1;
62 static int portnumber = 0;
63 static int prev_stats_len = 0;
64 static int scp_unsafe_mode = 0;
65 static char *password = NULL;
67 /* GUI Adaptation - Sept 2000 */
68 #define NAME_STR_MAX 2048
69 static char statname[NAME_STR_MAX + 1];
70 static unsigned long statsize = 0;
71 static unsigned long statdone = 0;
72 static unsigned long stateta = 0;
73 static unsigned long statratebs = 0;
74 static int statperct = 0;
75 static unsigned long statelapsed = 0;
76 static int gui_mode = 0;
77 static char *gui_hwnd = NULL;
78 static int using_sftp = 0;
80 static void source(char *src);
81 static void rsource(char *src);
82 static void sink(char *targ, char *src);
83 /* GUI Adaptation - Sept 2000 */
84 static void tell_char(FILE * stream, char c);
85 static void tell_str(FILE * stream, char *str);
86 static void tell_user(FILE * stream, char *fmt, ...);
87 static void gui_update_stats(char *name, unsigned long size,
88 int percentage, unsigned long elapsed,
89 unsigned long done, unsigned long eta,
90 unsigned long ratebs);
93 * The maximum amount of queued data we accept before we stop and
94 * wait for the server to process some.
96 #define MAX_SCP_BUFSIZE 16384
98 void logevent(char *string)
102 void ldisc_send(char *buf, int len, int interactive)
105 * This is only here because of the calls to ldisc_send(NULL,
106 * 0) in ssh.c. Nothing in PSCP actually needs to use the ldisc
107 * as an ldisc. So if we get called with any real data, I want
113 void verify_ssh_host_key(char *host, int port, char *keytype,
114 char *keystr, char *fingerprint)
120 static const char absentmsg[] =
121 "The server's host key is not cached in the registry. You\n"
122 "have no guarantee that the server is the computer you\n"
124 "The server's key fingerprint is:\n"
126 "If you trust this host, enter \"y\" to add the key to\n"
127 "PuTTY's cache and carry on connecting.\n"
128 "If you want to carry on connecting just once, without\n"
129 "adding the key to the cache, enter \"n\".\n"
130 "If you do not trust this host, press Return to abandon the\n"
132 "Store key in cache? (y/n) ";
134 static const char wrongmsg[] =
135 "WARNING - POTENTIAL SECURITY BREACH!\n"
136 "The server's host key does not match the one PuTTY has\n"
137 "cached in the registry. This means that either the\n"
138 "server administrator has changed the host key, or you\n"
139 "have actually connected to another computer pretending\n"
140 "to be the server.\n"
141 "The new key fingerprint is:\n"
143 "If you were expecting this change and trust the new key,\n"
144 "enter \"y\" to update PuTTY's cache and continue connecting.\n"
145 "If you want to carry on connecting but without updating\n"
146 "the cache, enter \"n\".\n"
147 "If you want to abandon the connection completely, press\n"
148 "Return to cancel. Pressing Return is the ONLY guaranteed\n"
150 "Update cached key? (y/n, Return cancels connection) ";
152 static const char abandoned[] = "Connection abandoned.\n";
157 * Verify the key against the registry.
159 ret = verify_host_key(host, port, keytype, keystr);
161 if (ret == 0) /* success - key matched OK */
164 if (ret == 2) { /* key was different */
165 fprintf(stderr, wrongmsg, fingerprint);
168 if (ret == 1) { /* key was absent */
169 fprintf(stderr, absentmsg, fingerprint);
173 hin = GetStdHandle(STD_INPUT_HANDLE);
174 GetConsoleMode(hin, &savemode);
175 SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
176 ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
177 ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
178 SetConsoleMode(hin, savemode);
180 if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') {
181 if (line[0] == 'y' || line[0] == 'Y')
182 store_host_key(host, port, keytype, keystr);
184 fprintf(stderr, abandoned);
190 * Ask whether the selected cipher is acceptable (since it was
191 * below the configured 'warn' threshold).
192 * cs: 0 = both ways, 1 = client->server, 2 = server->client
194 void askcipher(char *ciphername, int cs)
199 static const char msg[] =
200 "The first %scipher supported by the server is\n"
201 "%s, which is below the configured warning threshold.\n"
202 "Continue with connection? (y/n) ";
203 static const char abandoned[] = "Connection abandoned.\n";
209 (cs == 1) ? "client-to-server " :
214 hin = GetStdHandle(STD_INPUT_HANDLE);
215 GetConsoleMode(hin, &savemode);
216 SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
217 ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
218 ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
219 SetConsoleMode(hin, savemode);
221 if (line[0] == 'y' || line[0] == 'Y') {
224 fprintf(stderr, abandoned);
230 * Ask whether to wipe a session log file before writing to it.
231 * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
233 int askappend(char *filename)
238 static const char msgtemplate[] =
239 "The session log file \"%.*s\" already exists.\n"
240 "You can overwrite it with a new session log,\n"
241 "append your session log to the end of it,\n"
242 "or disable session logging for this session.\n"
243 "Enter \"y\" to wipe the file, \"n\" to append to it,\n"
244 "or just press Return to disable logging.\n"
245 "Wipe the log file? (y/n, Return cancels logging) ";
249 fprintf(stderr, msgtemplate, FILENAME_MAX, filename);
252 hin = GetStdHandle(STD_INPUT_HANDLE);
253 GetConsoleMode(hin, &savemode);
254 SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
255 ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
256 ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
257 SetConsoleMode(hin, savemode);
259 if (line[0] == 'y' || line[0] == 'Y')
261 else if (line[0] == 'n' || line[0] == 'N')
268 * Warn about the obsolescent key file format.
270 void old_keyfile_warning(void)
272 static const char message[] =
273 "You are loading an SSH 2 private key which has an\n"
274 "old version of the file format. This means your key\n"
275 "file is not fully tamperproof. Future versions of\n"
276 "PuTTY may stop supporting this private key format,\n"
277 "so we recommend you convert your key to the new\n"
280 "Once the key is loaded into PuTTYgen, you can perform\n"
281 "this conversion simply by saving it again.\n";
283 fputs(message, stderr);
286 /* GUI Adaptation - Sept 2000 */
287 static void send_msg(HWND h, UINT message, WPARAM wParam)
289 while (!PostMessage(h, message, wParam, 0))
293 static void tell_char(FILE * stream, char c)
298 unsigned int msg_id = WM_STD_OUT_CHAR;
299 if (stream == stderr)
300 msg_id = WM_STD_ERR_CHAR;
301 send_msg((HWND) atoi(gui_hwnd), msg_id, (WPARAM) c);
305 static void tell_str(FILE * stream, char *str)
309 for (i = 0; i < strlen(str); ++i)
310 tell_char(stream, str[i]);
313 static void tell_user(FILE * stream, char *fmt, ...)
315 char str[0x100]; /* Make the size big enough */
318 vsprintf(str, fmt, ap);
321 tell_str(stream, str);
324 static void gui_update_stats(char *name, unsigned long size,
325 int percentage, unsigned long elapsed,
326 unsigned long done, unsigned long eta,
327 unsigned long ratebs)
331 if (strcmp(name, statname) != 0) {
332 for (i = 0; i < strlen(name); ++i)
333 send_msg((HWND) atoi(gui_hwnd), WM_STATS_CHAR,
335 send_msg((HWND) atoi(gui_hwnd), WM_STATS_CHAR, (WPARAM) '\n');
336 strcpy(statname, name);
338 if (statsize != size) {
339 send_msg((HWND) atoi(gui_hwnd), WM_STATS_SIZE, (WPARAM) size);
342 if (statdone != done) {
343 send_msg((HWND) atoi(gui_hwnd), WM_STATS_DONE, (WPARAM) done);
346 if (stateta != eta) {
347 send_msg((HWND) atoi(gui_hwnd), WM_STATS_ETA, (WPARAM) eta);
350 if (statratebs != ratebs) {
351 send_msg((HWND) atoi(gui_hwnd), WM_STATS_RATEBS, (WPARAM) ratebs);
354 if (statelapsed != elapsed) {
355 send_msg((HWND) atoi(gui_hwnd), WM_STATS_ELAPSED,
357 statelapsed = elapsed;
359 if (statperct != percentage) {
360 send_msg((HWND) atoi(gui_hwnd), WM_STATS_PERCENT,
361 (WPARAM) percentage);
362 statperct = percentage;
367 * Print an error message and perform a fatal exit.
369 void fatalbox(char *fmt, ...)
371 char str[0x100]; /* Make the size big enough */
374 strcpy(str, "Fatal: ");
375 vsprintf(str + strlen(str), fmt, ap);
378 tell_str(stderr, str);
382 unsigned int msg_id = WM_RET_ERR_CNT;
384 msg_id = WM_LS_RET_ERR_CNT;
386 ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
387 0 /*lParam */ ))SleepEx(1000, TRUE);
392 void connection_fatal(char *fmt, ...)
394 char str[0x100]; /* Make the size big enough */
397 strcpy(str, "Fatal: ");
398 vsprintf(str + strlen(str), fmt, ap);
401 tell_str(stderr, str);
405 unsigned int msg_id = WM_RET_ERR_CNT;
407 msg_id = WM_LS_RET_ERR_CNT;
409 ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
410 0 /*lParam */ ))SleepEx(1000, TRUE);
417 * Be told what socket we're supposed to be using.
419 static SOCKET scp_ssh_socket;
420 char *do_select(SOCKET skt, int startup)
423 scp_ssh_socket = skt;
425 scp_ssh_socket = INVALID_SOCKET;
428 extern int select_result(WPARAM, LPARAM);
431 * Receive a block of data from the SSH link. Block until all data
434 * To do this, we repeatedly call the SSH protocol module, with our
435 * own trap in from_backend() to catch the data that comes back. We
436 * do this until we have enough data.
439 static unsigned char *outptr; /* where to put the data */
440 static unsigned outlen; /* how much data required */
441 static unsigned char *pending = NULL; /* any spare data */
442 static unsigned pendlen = 0, pendsize = 0; /* length and phys. size of buffer */
443 int from_backend(int is_stderr, char *data, int datalen)
445 unsigned char *p = (unsigned char *) data;
446 unsigned len = (unsigned) datalen;
449 * stderr data is just spouted to local stderr and otherwise
453 fwrite(data, 1, len, stderr);
458 * If this is before the real session begins, just return.
464 unsigned used = outlen;
467 memcpy(outptr, p, used);
475 if (pendsize < pendlen + len) {
476 pendsize = pendlen + len + 4096;
477 pending = (pending ? srealloc(pending, pendsize) :
480 fatalbox("Out of memory");
482 memcpy(pending + pendlen, p, len);
488 static int scp_process_network_event(void)
493 FD_SET(scp_ssh_socket, &readfds);
494 if (select(1, &readfds, NULL, NULL, NULL) < 0)
496 select_result((WPARAM) scp_ssh_socket, (LPARAM) FD_READ);
499 static int ssh_scp_recv(unsigned char *buf, int len)
505 * See if the pending-input block contains some of what we
509 unsigned pendused = pendlen;
510 if (pendused > outlen)
512 memcpy(outptr, pending, pendused);
513 memmove(pending, pending + pendused, pendlen - pendused);
527 if (!scp_process_network_event())
535 * Loop through the ssh connection and authentication process.
537 static void ssh_scp_init(void)
539 if (scp_ssh_socket == INVALID_SOCKET)
541 while (!back->sendok()) {
544 FD_SET(scp_ssh_socket, &readfds);
545 if (select(1, &readfds, NULL, NULL, NULL) < 0)
547 select_result((WPARAM) scp_ssh_socket, (LPARAM) FD_READ);
549 using_sftp = !ssh_fallback_cmd;
553 * Print an error message and exit after closing the SSH link.
555 static void bump(char *fmt, ...)
557 char str[0x100]; /* Make the size big enough */
560 strcpy(str, "Fatal: ");
561 vsprintf(str + strlen(str), fmt, ap);
564 tell_str(stderr, str);
567 if (back != NULL && back->socket() != NULL) {
569 back->special(TS_EOF);
570 ssh_scp_recv(&ch, 1);
574 unsigned int msg_id = WM_RET_ERR_CNT;
576 msg_id = WM_LS_RET_ERR_CNT;
578 ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
579 0 /*lParam */ ))SleepEx(1000, TRUE);
585 static int get_line(const char *prompt, char *str, int maxlen, int is_pw)
588 DWORD savemode, newmode, i;
590 if (is_pw && password) {
591 static int tried_once = 0;
596 strncpy(str, password, maxlen);
597 str[maxlen - 1] = '\0';
603 /* GUI Adaptation - Sept 2000 */
608 hin = GetStdHandle(STD_INPUT_HANDLE);
609 hout = GetStdHandle(STD_OUTPUT_HANDLE);
610 if (hin == INVALID_HANDLE_VALUE || hout == INVALID_HANDLE_VALUE)
611 bump("Cannot get standard input/output handles");
613 GetConsoleMode(hin, &savemode);
614 newmode = savemode | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT;
616 newmode &= ~ENABLE_ECHO_INPUT;
618 newmode |= ENABLE_ECHO_INPUT;
619 SetConsoleMode(hin, newmode);
621 WriteFile(hout, prompt, strlen(prompt), &i, NULL);
622 ReadFile(hin, str, maxlen - 1, &i, NULL);
624 SetConsoleMode(hin, savemode);
626 if ((int) i > maxlen)
633 WriteFile(hout, "\r\n", 2, &i, NULL);
640 * Open an SSH connection to user@host and execute cmd.
642 static void do_cmd(char *host, char *user, char *cmd)
644 char *err, *realhost;
647 if (host == NULL || host[0] == '\0')
648 bump("Empty host name");
650 /* Try to load settings for this host */
651 do_defaults(host, &cfg);
652 if (cfg.host[0] == '\0') {
653 /* No settings for this host; use defaults */
654 do_defaults(NULL, &cfg);
655 strncpy(cfg.host, host, sizeof(cfg.host) - 1);
656 cfg.host[sizeof(cfg.host) - 1] = '\0';
661 * Trim leading whitespace off the hostname if it's there.
664 int space = strspn(cfg.host, " \t");
665 memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space);
668 /* See if host is of the form user@host */
669 if (cfg.host[0] != '\0') {
670 char *atsign = strchr(cfg.host, '@');
671 /* Make sure we're not overflowing the user field */
673 if (atsign - cfg.host < sizeof cfg.username) {
674 strncpy(cfg.username, cfg.host, atsign - cfg.host);
675 cfg.username[atsign - cfg.host] = '\0';
677 memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1));
682 * Trim a colon suffix off the hostname if it's there.
684 cfg.host[strcspn(cfg.host, ":")] = '\0';
687 if (user != NULL && user[0] != '\0') {
688 strncpy(cfg.username, user, sizeof(cfg.username) - 1);
689 cfg.username[sizeof(cfg.username) - 1] = '\0';
690 } else if (cfg.username[0] == '\0') {
692 if (GetUserName(user, &namelen) == FALSE)
693 bump("Empty user name");
694 user = smalloc(namelen * sizeof(char));
695 GetUserName(user, &namelen);
697 tell_user(stderr, "Guessing user name: %s", user);
698 strncpy(cfg.username, user, sizeof(cfg.username) - 1);
699 cfg.username[sizeof(cfg.username) - 1] = '\0';
703 if (cfg.protocol != PROT_SSH)
707 cfg.port = portnumber;
710 * Disable scary things which shouldn't be enabled for simple
711 * things like SCP and SFTP: agent forwarding, port forwarding,
716 cfg.portfwd[0] = cfg.portfwd[1] = '\0';
719 * Attempt to start the SFTP subsystem as a first choice,
720 * falling back to the provided scp command if that fails.
722 strcpy(cfg.remote_cmd, "sftp");
723 cfg.ssh_subsys = TRUE;
724 cfg.remote_cmd_ptr2 = cmd;
725 cfg.ssh_subsys2 = FALSE;
730 err = back->init(cfg.host, cfg.port, &realhost, 0);
732 bump("ssh_init: %s", err);
734 if (verbose && realhost != NULL)
735 tell_user(stderr, "Connected to %s\n", realhost);
740 * Update statistic information about current file.
742 static void print_stats(char *name, unsigned long size, unsigned long done,
743 time_t start, time_t now)
752 elap = (unsigned long) difftime(now, start);
755 ratebs = (float) done / elap;
757 ratebs = (float) done;
762 eta = (unsigned long) ((size - done) / ratebs);
763 sprintf(etastr, "%02ld:%02ld:%02ld",
764 eta / 3600, (eta % 3600) / 60, eta % 60);
766 pct = (int) (100 * (done * 1.0 / size));
769 /* GUI Adaptation - Sept 2000 */
770 gui_update_stats(name, size, pct, elap, done, eta,
771 (unsigned long) ratebs);
773 len = printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%",
774 name, done / 1024, ratebs / 1024.0, etastr, pct);
775 if (len < prev_stats_len)
776 printf("%*s", prev_stats_len - len, "");
777 prev_stats_len = len;
785 * Find a colon in str and return a pointer to the colon.
786 * This is used to separate hostname from filename.
788 static char *colon(char *str)
790 /* We ignore a leading colon, since the hostname cannot be
791 empty. We also ignore a colon as second character because
792 of filenames like f:myfile.txt. */
793 if (str[0] == '\0' || str[0] == ':' || str[1] == ':')
795 while (*str != '\0' && *str != ':' && *str != '/' && *str != '\\')
804 * Return a pointer to the portion of str that comes after the last
805 * slash (or backslash or colon, if `local' is TRUE).
807 static char *stripslashes(char *str, int local)
812 p = strchr(str, ':');
816 p = strrchr(str, '/');
820 p = strrchr(str, '\\');
828 * Determine whether a string is entirely composed of dots.
830 static int is_dots(char *str)
832 return str[strspn(str, ".")] == '\0';
836 * Wait for a response from the other side.
837 * Return 0 if ok, -1 if error.
839 static int response(void)
841 char ch, resp, rbuf[2048];
844 if (ssh_scp_recv(&resp, 1) <= 0)
845 bump("Lost connection");
855 case 2: /* fatal error */
857 if (ssh_scp_recv(&ch, 1) <= 0)
858 bump("Protocol error: Lost connection");
860 } while (p < sizeof(rbuf) && ch != '\n');
863 tell_user(stderr, "%s\n", rbuf);
871 int sftp_recvdata(char *buf, int len)
873 return ssh_scp_recv(buf, len);
875 int sftp_senddata(char *buf, int len)
877 back->send((unsigned char *) buf, len);
881 /* ----------------------------------------------------------------------
882 * sftp-based replacement for the hacky `pscp -ls'.
884 static int sftp_ls_compare(const void *av, const void *bv)
886 const struct fxp_name *a = (const struct fxp_name *) av;
887 const struct fxp_name *b = (const struct fxp_name *) bv;
888 return strcmp(a->filename, b->filename);
890 void scp_sftp_listdir(char *dirname)
892 struct fxp_handle *dirh;
893 struct fxp_names *names;
894 struct fxp_name *ournames;
895 int nnames, namesize;
898 printf("Listing directory %s\n", dirname);
900 dirh = fxp_opendir(dirname);
902 printf("Unable to open %s: %s\n", dirname, fxp_error());
904 nnames = namesize = 0;
909 names = fxp_readdir(dirh);
911 if (fxp_error_type() == SSH_FX_EOF)
913 printf("Reading directory %s: %s\n", dirname, fxp_error());
916 if (names->nnames == 0) {
917 fxp_free_names(names);
921 if (nnames + names->nnames >= namesize) {
922 namesize += names->nnames + 128;
924 srealloc(ournames, namesize * sizeof(*ournames));
927 for (i = 0; i < names->nnames; i++)
928 ournames[nnames++] = names->names[i];
930 names->nnames = 0; /* prevent free_names */
931 fxp_free_names(names);
936 * Now we have our filenames. Sort them by actual file
937 * name, and then output the longname parts.
939 qsort(ournames, nnames, sizeof(*ournames), sftp_ls_compare);
944 for (i = 0; i < nnames; i++)
945 printf("%s\n", ournames[i].longname);
949 /* ----------------------------------------------------------------------
950 * Helper routines that contain the actual SCP protocol elements,
951 * implemented both as SCP1 and SFTP.
954 static struct scp_sftp_dirstack {
955 struct scp_sftp_dirstack *next;
956 struct fxp_name *names;
957 int namepos, namelen;
960 int matched_something; /* wildcard match set was non-empty */
961 } *scp_sftp_dirstack_head;
962 static char *scp_sftp_remotepath, *scp_sftp_currentname;
963 static char *scp_sftp_wildcard;
964 static int scp_sftp_targetisdir, scp_sftp_donethistarget;
965 static int scp_sftp_preserve, scp_sftp_recursive;
966 static unsigned long scp_sftp_mtime, scp_sftp_atime;
967 static int scp_has_times;
968 static struct fxp_handle *scp_sftp_filehandle;
969 static uint64 scp_sftp_fileoffset;
971 void scp_source_setup(char *target, int shouldbedir)
975 * Find out whether the target filespec is in fact a
978 struct fxp_attrs attrs;
980 if (!fxp_stat(target, &attrs) ||
981 !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS))
982 scp_sftp_targetisdir = 0;
984 scp_sftp_targetisdir = (attrs.permissions & 0040000) != 0;
986 if (shouldbedir && !scp_sftp_targetisdir) {
987 bump("pscp: remote filespec %s: not a directory\n", target);
990 scp_sftp_remotepath = dupstr(target);
998 int scp_send_errmsg(char *str)
1001 /* do nothing; we never need to send our errors to the server */
1003 back->send("\001", 1); /* scp protocol error prefix */
1004 back->send(str, strlen(str));
1006 return 0; /* can't fail */
1009 int scp_send_filetimes(unsigned long mtime, unsigned long atime)
1012 scp_sftp_mtime = mtime;
1013 scp_sftp_atime = atime;
1018 sprintf(buf, "T%lu 0 %lu 0\n", mtime, atime);
1019 back->send(buf, strlen(buf));
1024 int scp_send_filename(char *name, unsigned long size, int modes)
1028 if (scp_sftp_targetisdir) {
1029 fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
1031 fullname = dupstr(scp_sftp_remotepath);
1033 scp_sftp_filehandle =
1034 fxp_open(fullname, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC);
1035 if (!scp_sftp_filehandle) {
1036 tell_user(stderr, "pscp: unable to open %s: %s",
1037 fullname, fxp_error());
1041 scp_sftp_fileoffset = uint64_make(0, 0);
1046 sprintf(buf, "C%04o %lu ", modes, size);
1047 back->send(buf, strlen(buf));
1048 back->send(name, strlen(name));
1049 back->send("\n", 1);
1054 int scp_send_filedata(char *data, int len)
1057 if (!scp_sftp_filehandle) {
1060 if (!fxp_write(scp_sftp_filehandle, data, scp_sftp_fileoffset, len)) {
1061 tell_user(stderr, "error while writing: %s\n", fxp_error());
1065 scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, len);
1068 int bufsize = back->send(data, len);
1071 * If the network transfer is backing up - that is, the
1072 * remote site is not accepting data as fast as we can
1073 * produce it - then we must loop on network events until
1074 * we have space in the buffer again.
1076 while (bufsize > MAX_SCP_BUFSIZE) {
1077 if (!scp_process_network_event())
1079 bufsize = back->sendbuffer();
1086 int scp_send_finish(void)
1089 struct fxp_attrs attrs;
1090 if (!scp_sftp_filehandle) {
1093 if (scp_has_times) {
1094 attrs.flags = SSH_FILEXFER_ATTR_ACMODTIME;
1095 attrs.atime = scp_sftp_atime;
1096 attrs.mtime = scp_sftp_mtime;
1097 if (!fxp_fsetstat(scp_sftp_filehandle, attrs)) {
1098 tell_user(stderr, "unable to set file times: %s\n", fxp_error());
1102 fxp_close(scp_sftp_filehandle);
1111 char *scp_save_remotepath(void)
1114 return scp_sftp_remotepath;
1119 void scp_restore_remotepath(char *data)
1122 scp_sftp_remotepath = data;
1125 int scp_send_dirname(char *name, int modes)
1130 struct fxp_attrs attrs;
1131 if (scp_sftp_targetisdir) {
1132 fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
1134 fullname = dupstr(scp_sftp_remotepath);
1138 * We don't worry about whether we managed to create the
1139 * directory, because if it exists already it's OK just to
1140 * use it. Instead, we will stat it afterwards, and if it
1141 * exists and is a directory we will assume we were either
1142 * successful or it didn't matter.
1144 if (!fxp_mkdir(fullname))
1147 err = "server reported no error";
1148 if (!fxp_stat(fullname, &attrs) ||
1149 !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) ||
1150 !(attrs.permissions & 0040000)) {
1151 tell_user(stderr, "unable to create directory %s: %s",
1157 scp_sftp_remotepath = fullname;
1162 sprintf(buf, "D%04o 0 ", modes);
1163 back->send(buf, strlen(buf));
1164 back->send(name, strlen(name));
1165 back->send("\n", 1);
1170 int scp_send_enddir(void)
1173 sfree(scp_sftp_remotepath);
1176 back->send("E\n", 2);
1182 * Yes, I know; I have an scp_sink_setup _and_ an scp_sink_init.
1183 * That's bad. The difference is that scp_sink_setup is called once
1184 * right at the start, whereas scp_sink_init is called to
1185 * initialise every level of recursion in the protocol.
1187 int scp_sink_setup(char *source, int preserve, int recursive)
1192 * It's possible that the source string we've been given
1193 * contains a wildcard. If so, we must split the directory
1194 * away from the wildcard itself (throwing an error if any
1195 * wildcardness comes before the final slash) and arrange
1196 * things so that a dirstack entry will be set up.
1198 newsource = smalloc(1+strlen(source));
1199 if (!wc_unescape(newsource, source)) {
1200 /* Yes, here we go; it's a wildcard. Bah. */
1201 char *dupsource, *lastpart, *dirpart, *wildcard;
1202 dupsource = dupstr(source);
1203 lastpart = stripslashes(dupsource, 0);
1204 wildcard = dupstr(lastpart);
1206 if (*dupsource && dupsource[1]) {
1208 * The remains of dupsource are at least two
1209 * characters long, meaning the pathname wasn't
1210 * empty or just `/'. Hence, we remove the trailing
1213 lastpart[-1] = '\0';
1214 } else if (!*dupsource) {
1216 * The remains of dupsource are _empty_ - the whole
1217 * pathname was a wildcard. Hence we need to
1218 * replace it with ".".
1221 dupsource = dupstr(".");
1225 * Now we have separated our string into dupsource (the
1226 * directory part) and wildcard. Both of these will
1227 * need freeing at some point. Next step is to remove
1228 * wildcard escapes from the directory part, throwing
1229 * an error if it contains a real wildcard.
1231 dirpart = smalloc(1+strlen(dupsource));
1232 if (!wc_unescape(dirpart, dupsource)) {
1233 tell_user(stderr, "%s: multiple-level wildcards unsupported",
1243 * Now we have dirpart (unescaped, ie a valid remote
1244 * path), and wildcard (a wildcard). This will be
1245 * sufficient to arrange a dirstack entry.
1247 scp_sftp_remotepath = dirpart;
1248 scp_sftp_wildcard = wildcard;
1251 scp_sftp_remotepath = newsource;
1252 scp_sftp_wildcard = NULL;
1254 scp_sftp_preserve = preserve;
1255 scp_sftp_recursive = recursive;
1256 scp_sftp_donethistarget = 0;
1257 scp_sftp_dirstack_head = NULL;
1262 int scp_sink_init(void)
1270 #define SCP_SINK_FILE 1
1271 #define SCP_SINK_DIR 2
1272 #define SCP_SINK_ENDDIR 3
1273 #define SCP_SINK_RETRY 4 /* not an action; just try again */
1274 struct scp_sink_action {
1275 int action; /* FILE, DIR, ENDDIR */
1276 char *buf; /* will need freeing after use */
1277 char *name; /* filename or dirname (not ENDDIR) */
1278 int mode; /* access mode (not ENDDIR) */
1279 unsigned long size; /* file size (not ENDDIR) */
1280 int settime; /* 1 if atime and mtime are filled */
1281 unsigned long atime, mtime; /* access times for the file */
1284 int scp_get_sink_action(struct scp_sink_action *act)
1288 int must_free_fname;
1289 struct fxp_attrs attrs;
1292 if (!scp_sftp_dirstack_head) {
1293 if (!scp_sftp_donethistarget) {
1295 * Simple case: we are only dealing with one file.
1297 fname = scp_sftp_remotepath;
1298 must_free_fname = 0;
1299 scp_sftp_donethistarget = 1;
1302 * Even simpler case: one file _which we've done_.
1303 * Return 1 (finished).
1309 * We're now in the middle of stepping through a list
1310 * of names returned from fxp_readdir(); so let's carry
1313 struct scp_sftp_dirstack *head = scp_sftp_dirstack_head;
1314 while (head->namepos < head->namelen &&
1315 (is_dots(head->names[head->namepos].filename) ||
1317 !wc_match(head->wildcard,
1318 head->names[head->namepos].filename))))
1319 head->namepos++; /* skip . and .. */
1320 if (head->namepos < head->namelen) {
1321 head->matched_something = 1;
1322 fname = dupcat(head->dirpath, "/",
1323 head->names[head->namepos++].filename,
1325 must_free_fname = 1;
1328 * We've come to the end of the list; pop it off
1329 * the stack and return an ENDDIR action (or RETRY
1330 * if this was a wildcard match).
1332 if (head->wildcard) {
1333 act->action = SCP_SINK_RETRY;
1334 if (!head->matched_something) {
1335 tell_user(stderr, "pscp: wildcard '%s' matched "
1336 "no files", head->wildcard);
1339 sfree(head->wildcard);
1342 act->action = SCP_SINK_ENDDIR;
1345 sfree(head->dirpath);
1347 scp_sftp_dirstack_head = head->next;
1355 * Now we have a filename. Stat it, and see if it's a file
1358 ret = fxp_stat(fname, &attrs);
1359 if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) {
1360 tell_user(stderr, "unable to identify %s: %s", fname,
1361 ret ? "file type not supplied" : fxp_error());
1366 if (attrs.permissions & 0040000) {
1367 struct scp_sftp_dirstack *newitem;
1368 struct fxp_handle *dirhandle;
1369 int nnames, namesize;
1370 struct fxp_name *ournames;
1371 struct fxp_names *names;
1374 * It's a directory. If we're not in recursive mode,
1375 * this merits a complaint (which is fatal if the name
1376 * was specified directly, but not if it was matched by
1379 * We skip this complaint completely if
1380 * scp_sftp_wildcard is set, because that's an
1381 * indication that we're not actually supposed to
1382 * _recursively_ transfer the dir, just scan it for
1383 * things matching the wildcard.
1385 if (!scp_sftp_recursive && !scp_sftp_wildcard) {
1386 tell_user(stderr, "pscp: %s: is a directory", fname);
1388 if (must_free_fname) sfree(fname);
1389 if (scp_sftp_dirstack_head) {
1390 act->action = SCP_SINK_RETRY;
1398 * Otherwise, the fun begins. We must fxp_opendir() the
1399 * directory, slurp the filenames into memory, return
1400 * SCP_SINK_DIR (unless this is a wildcard match), and
1401 * set targetisdir. The next time we're called, we will
1402 * run through the list of filenames one by one,
1403 * matching them against a wildcard if present.
1405 * If targetisdir is _already_ set (meaning we're
1406 * already in the middle of going through another such
1407 * list), we must push the other (target,namelist) pair
1410 dirhandle = fxp_opendir(fname);
1412 tell_user(stderr, "scp: unable to open directory %s: %s",
1413 fname, fxp_error());
1414 if (must_free_fname) sfree(fname);
1418 nnames = namesize = 0;
1423 names = fxp_readdir(dirhandle);
1424 if (names == NULL) {
1425 if (fxp_error_type() == SSH_FX_EOF)
1427 tell_user(stderr, "scp: reading directory %s: %s\n",
1428 fname, fxp_error());
1429 if (must_free_fname) sfree(fname);
1434 if (names->nnames == 0) {
1435 fxp_free_names(names);
1438 if (nnames + names->nnames >= namesize) {
1439 namesize += names->nnames + 128;
1441 srealloc(ournames, namesize * sizeof(*ournames));
1443 for (i = 0; i < names->nnames; i++)
1444 ournames[nnames++] = names->names[i];
1445 names->nnames = 0; /* prevent free_names */
1446 fxp_free_names(names);
1448 fxp_close(dirhandle);
1450 newitem = smalloc(sizeof(struct scp_sftp_dirstack));
1451 newitem->next = scp_sftp_dirstack_head;
1452 newitem->names = ournames;
1453 newitem->namepos = 0;
1454 newitem->namelen = nnames;
1455 if (must_free_fname)
1456 newitem->dirpath = fname;
1458 newitem->dirpath = dupstr(fname);
1459 if (scp_sftp_wildcard) {
1460 newitem->wildcard = scp_sftp_wildcard;
1461 newitem->matched_something = 0;
1462 scp_sftp_wildcard = NULL;
1464 newitem->wildcard = NULL;
1466 scp_sftp_dirstack_head = newitem;
1468 if (newitem->wildcard) {
1469 act->action = SCP_SINK_RETRY;
1471 act->action = SCP_SINK_DIR;
1472 act->buf = dupstr(stripslashes(fname, 0));
1473 act->name = act->buf;
1474 act->size = 0; /* duhh, it's a directory */
1475 act->mode = 07777 & attrs.permissions;
1476 if (scp_sftp_preserve &&
1477 (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
1478 act->atime = attrs.atime;
1479 act->mtime = attrs.mtime;
1488 * It's a file. Return SCP_SINK_FILE.
1490 act->action = SCP_SINK_FILE;
1491 act->buf = dupstr(stripslashes(fname, 0));
1492 act->name = act->buf;
1493 if (attrs.flags & SSH_FILEXFER_ATTR_SIZE) {
1494 if (uint64_compare(attrs.size,
1495 uint64_make(0, ULONG_MAX)) > 0) {
1496 act->size = ULONG_MAX; /* *boggle* */
1498 act->size = attrs.size.lo;
1500 act->size = ULONG_MAX; /* no idea */
1501 act->mode = 07777 & attrs.permissions;
1502 if (scp_sftp_preserve &&
1503 (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
1504 act->atime = attrs.atime;
1505 act->mtime = attrs.mtime;
1509 if (must_free_fname)
1510 scp_sftp_currentname = fname;
1512 scp_sftp_currentname = dupstr(fname);
1527 if (ssh_scp_recv(&ch, 1) <= 0)
1530 bump("Protocol error: Unexpected newline");
1534 if (ssh_scp_recv(&ch, 1) <= 0)
1535 bump("Lost connection");
1538 act->buf = srealloc(act->buf, bufsize);
1541 } while (ch != '\n');
1542 act->buf[i - 1] = '\0';
1544 case '\01': /* error */
1545 tell_user(stderr, "%s\n", act->buf);
1547 continue; /* go round again */
1548 case '\02': /* fatal error */
1549 bump("%s", act->buf);
1552 act->action = SCP_SINK_ENDDIR;
1555 if (sscanf(act->buf, "%ld %*d %ld %*d",
1556 &act->mtime, &act->atime) == 2) {
1559 continue; /* go round again */
1561 bump("Protocol error: Illegal time format");
1564 act->action = (action == 'C' ? SCP_SINK_FILE : SCP_SINK_DIR);
1567 bump("Protocol error: Expected control record");
1570 * We will go round this loop only once, unless we hit
1577 * If we get here, we must have seen SCP_SINK_FILE or
1580 if (sscanf(act->buf, "%o %lu %n", &act->mode, &act->size, &i) != 2)
1581 bump("Protocol error: Illegal file descriptor format");
1582 act->name = act->buf + i;
1587 int scp_accept_filexfer(void)
1590 scp_sftp_filehandle =
1591 fxp_open(scp_sftp_currentname, SSH_FXF_READ);
1592 if (!scp_sftp_filehandle) {
1593 tell_user(stderr, "pscp: unable to open %s: %s",
1594 scp_sftp_currentname, fxp_error());
1598 scp_sftp_fileoffset = uint64_make(0, 0);
1599 sfree(scp_sftp_currentname);
1603 return 0; /* can't fail */
1607 int scp_recv_filedata(char *data, int len)
1610 int actuallen = fxp_read(scp_sftp_filehandle, data,
1611 scp_sftp_fileoffset, len);
1612 if (actuallen == -1 && fxp_error_type() != SSH_FX_EOF) {
1613 tell_user(stderr, "pscp: error while reading: %s", fxp_error());
1620 scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, actuallen);
1624 return ssh_scp_recv(data, len);
1628 int scp_finish_filerecv(void)
1631 fxp_close(scp_sftp_filehandle);
1639 /* ----------------------------------------------------------------------
1640 * Send an error message to the other side and to the screen.
1641 * Increment error counter.
1643 static void run_err(const char *fmt, ...)
1649 strcpy(str, "scp: ");
1650 vsprintf(str + strlen(str), fmt, ap);
1652 scp_send_errmsg(str);
1653 tell_user(stderr, "%s", str);
1658 * Execute the source part of the SCP protocol.
1660 static void source(char *src)
1667 unsigned long stat_bytes;
1668 time_t stat_starttime, stat_lasttime;
1670 attr = GetFileAttributes(src);
1671 if (attr == (DWORD) - 1) {
1672 run_err("%s: No such file or directory", src);
1676 if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1679 * Avoid . and .. directories.
1682 p = strrchr(src, '/');
1684 p = strrchr(src, '\\');
1689 if (!strcmp(p, ".") || !strcmp(p, ".."))
1690 /* skip . and .. */ ;
1694 run_err("%s: not a regular file", src);
1699 if ((last = strrchr(src, '/')) == NULL)
1703 if (strrchr(last, '\\') != NULL)
1704 last = strrchr(last, '\\') + 1;
1705 if (last == src && strchr(src, ':') != NULL)
1706 last = strchr(src, ':') + 1;
1708 f = CreateFile(src, GENERIC_READ, FILE_SHARE_READ, NULL,
1709 OPEN_EXISTING, 0, 0);
1710 if (f == INVALID_HANDLE_VALUE) {
1711 run_err("%s: Cannot open file", src);
1716 FILETIME actime, wrtime;
1717 unsigned long mtime, atime;
1718 GetFileTime(f, NULL, &actime, &wrtime);
1719 TIME_WIN_TO_POSIX(actime, atime);
1720 TIME_WIN_TO_POSIX(wrtime, mtime);
1721 if (scp_send_filetimes(mtime, atime))
1725 size = GetFileSize(f, NULL);
1727 tell_user(stderr, "Sending file %s, size=%lu", last, size);
1728 if (scp_send_filename(last, size, 0644))
1732 stat_starttime = time(NULL);
1735 for (i = 0; i < size; i += 4096) {
1736 char transbuf[4096];
1741 if (!ReadFile(f, transbuf, k, &j, NULL) || j != k) {
1744 bump("%s: Read error", src);
1746 if (scp_send_filedata(transbuf, k))
1747 bump("%s: Network error occurred", src);
1751 if (time(NULL) != stat_lasttime || i + k == size) {
1752 stat_lasttime = time(NULL);
1753 print_stats(last, size, stat_bytes,
1754 stat_starttime, stat_lasttime);
1761 (void) scp_send_finish();
1765 * Recursively send the contents of a directory.
1767 static void rsource(char *src)
1769 char *last, *findfile;
1772 WIN32_FIND_DATA fdat;
1775 if ((last = strrchr(src, '/')) == NULL)
1779 if (strrchr(last, '\\') != NULL)
1780 last = strrchr(last, '\\') + 1;
1781 if (last == src && strchr(src, ':') != NULL)
1782 last = strchr(src, ':') + 1;
1784 /* maybe send filetime */
1786 save_target = scp_save_remotepath();
1789 tell_user(stderr, "Entering directory: %s", last);
1790 if (scp_send_dirname(last, 0755))
1793 findfile = dupcat(src, "/*", NULL);
1794 dir = FindFirstFile(findfile, &fdat);
1795 ok = (dir != INVALID_HANDLE_VALUE);
1797 if (strcmp(fdat.cFileName, ".") == 0 ||
1798 strcmp(fdat.cFileName, "..") == 0) {
1799 /* ignore . and .. */
1801 char *foundfile = dupcat(src, "/", fdat.cFileName, NULL);
1805 ok = FindNextFile(dir, &fdat);
1810 (void) scp_send_enddir();
1812 scp_restore_remotepath(save_target);
1816 * Execute the sink part of the SCP protocol.
1818 static void sink(char *targ, char *src)
1825 unsigned long received;
1827 unsigned long stat_bytes;
1828 time_t stat_starttime, stat_lasttime;
1831 attr = GetFileAttributes(targ);
1832 if (attr != (DWORD) - 1 && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0)
1835 if (targetshouldbedirectory && !targisdir)
1836 bump("%s: Not a directory", targ);
1840 struct scp_sink_action act;
1841 if (scp_get_sink_action(&act))
1844 if (act.action == SCP_SINK_ENDDIR)
1847 if (act.action == SCP_SINK_RETRY)
1852 * Prevent the remote side from maliciously writing to
1853 * files outside the target area by sending a filename
1854 * containing `../'. In fact, it shouldn't be sending
1855 * filenames with any slashes or colons in at all; so
1856 * we'll find the last slash, backslash or colon in the
1857 * filename and use only the part after that. (And
1860 * In addition, we also ensure here that if we're
1861 * copying a single file and the target is a directory
1862 * (common usage: `pscp host:filename .') the remote
1863 * can't send us a _different_ file name. We can
1864 * distinguish this case because `src' will be non-NULL
1865 * and the last component of that will fail to match
1866 * (the last component of) the name sent.
1868 * Well, not always; if `src' is a wildcard, we do
1869 * expect to get back filenames that don't correspond
1870 * exactly to it. Ideally in this case, we would like
1871 * to ensure that the returned filename actually
1872 * matches the wildcard pattern - but one of SCP's
1873 * protocol infelicities is that wildcard matching is
1874 * done at the server end _by the server's rules_ and
1875 * so in general this is infeasible. Hence, we only
1876 * accept filenames that don't correspond to `src' if
1877 * unsafe mode is enabled or we are using SFTP (which
1878 * resolves remote wildcards on the client side and can
1881 char *striptarget, *stripsrc;
1883 striptarget = stripslashes(act.name, 1);
1884 if (striptarget != act.name) {
1885 tell_user(stderr, "warning: remote host sent a compound"
1886 " pathname '%s'", act.name);
1887 tell_user(stderr, " renaming local file to '%s'",
1892 * Also check to see if the target filename is '.' or
1893 * '..', or indeed '...' and so on because Windows
1894 * appears to interpret those like '..'.
1896 if (is_dots(striptarget)) {
1897 bump("security violation: remote host attempted to write to"
1898 " a '.' or '..' path!");
1902 stripsrc = stripslashes(src, 1);
1903 if (strcmp(striptarget, stripsrc) &&
1904 !using_sftp && !scp_unsafe_mode) {
1905 tell_user(stderr, "warning: remote host tried to write "
1906 "to a file called '%s'", striptarget);
1907 tell_user(stderr, " when we requested a file "
1908 "called '%s'.", stripsrc);
1909 tell_user(stderr, " If this is a wildcard, "
1910 "consider upgrading to SSH 2 or using");
1911 tell_user(stderr, " the '-unsafe' option. Renaming"
1912 " of this file has been disallowed.");
1913 /* Override the name the server provided with our own. */
1914 striptarget = stripsrc;
1918 if (targ[0] != '\0')
1919 destfname = dupcat(targ, "\\", striptarget, NULL);
1921 destfname = dupstr(striptarget);
1924 * In this branch of the if, the target area is a
1925 * single file with an explicitly specified name in any
1926 * case, so there's no danger.
1928 destfname = dupstr(targ);
1930 attr = GetFileAttributes(destfname);
1931 exists = (attr != (DWORD) - 1);
1933 if (act.action == SCP_SINK_DIR) {
1934 if (exists && (attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
1935 run_err("%s: Not a directory", destfname);
1939 if (!CreateDirectory(destfname, NULL)) {
1940 run_err("%s: Cannot create directory", destfname);
1944 sink(destfname, NULL);
1945 /* can we set the timestamp for directories ? */
1949 f = CreateFile(destfname, GENERIC_WRITE, 0, NULL,
1950 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
1951 if (f == INVALID_HANDLE_VALUE) {
1952 run_err("%s: Cannot create file", destfname);
1956 if (scp_accept_filexfer())
1960 stat_starttime = time(NULL);
1962 stat_name = stripslashes(destfname, 1);
1965 while (received < act.size) {
1966 char transbuf[4096];
1967 DWORD blksize, read, written;
1969 if (blksize > act.size - received)
1970 blksize = act.size - received;
1971 read = scp_recv_filedata(transbuf, blksize);
1973 bump("Lost connection");
1976 if (!WriteFile(f, transbuf, read, &written, NULL) ||
1979 /* FIXME: in sftp we can actually abort the transfer */
1981 printf("\r%-25.25s | %50s\n",
1983 "Write error.. waiting for end of file");
1988 if (time(NULL) > stat_lasttime ||
1989 received + read == act.size) {
1990 stat_lasttime = time(NULL);
1991 print_stats(stat_name, act.size, stat_bytes,
1992 stat_starttime, stat_lasttime);
1998 FILETIME actime, wrtime;
1999 TIME_POSIX_TO_WIN(act.atime, actime);
2000 TIME_POSIX_TO_WIN(act.mtime, wrtime);
2001 SetFileTime(f, NULL, &actime, &wrtime);
2006 run_err("%s: Write error", destfname);
2009 (void) scp_finish_filerecv();
2016 * We will copy local files to a remote server.
2018 static void toremote(int argc, char *argv[])
2020 char *src, *targ, *host, *user;
2024 targ = argv[argc - 1];
2026 /* Separate host from filename */
2030 bump("targ == NULL in toremote()");
2034 /* Substitute "." for emtpy target */
2036 /* Separate host and username */
2038 host = strrchr(host, '@');
2049 /* Find out if the source filespec covers multiple files
2050 if so, we should set the targetshouldbedirectory flag */
2052 WIN32_FIND_DATA fdat;
2053 if (colon(argv[0]) != NULL)
2054 bump("%s: Remote to remote not supported", argv[0]);
2055 fh = FindFirstFile(argv[0], &fdat);
2056 if (fh == INVALID_HANDLE_VALUE)
2057 bump("%s: No such file or directory\n", argv[0]);
2058 if (FindNextFile(fh, &fdat))
2059 targetshouldbedirectory = 1;
2063 cmd = smalloc(strlen(targ) + 100);
2064 sprintf(cmd, "scp%s%s%s%s -t %s",
2065 verbose ? " -v" : "",
2066 recursive ? " -r" : "",
2067 preserve ? " -p" : "",
2068 targetshouldbedirectory ? " -d" : "", targ);
2069 do_cmd(host, user, cmd);
2072 scp_source_setup(targ, targetshouldbedirectory);
2074 for (i = 0; i < argc - 1; i++) {
2075 char *srcpath, *last;
2077 WIN32_FIND_DATA fdat;
2079 if (colon(src) != NULL) {
2080 tell_user(stderr, "%s: Remote to remote not supported\n", src);
2086 * Trim off the last pathname component of `src', to
2087 * provide the base pathname which will be prepended to
2088 * filenames returned from Find{First,Next}File.
2090 srcpath = dupstr(src);
2091 last = stripslashes(srcpath, 1);
2094 dir = FindFirstFile(src, &fdat);
2095 if (dir == INVALID_HANDLE_VALUE) {
2096 run_err("%s: No such file or directory", src);
2102 * Ensure that . and .. are never matched by wildcards,
2103 * but only by deliberate action.
2105 if (!strcmp(fdat.cFileName, ".") ||
2106 !strcmp(fdat.cFileName, "..")) {
2108 * Find*File has returned a special dir. We require
2109 * that _either_ `src' ends in a backslash followed
2110 * by that string, _or_ `src' is precisely that
2113 int len = strlen(src), dlen = strlen(fdat.cFileName);
2114 if (len == dlen && !strcmp(src, fdat.cFileName)) {
2116 } else if (len > dlen + 1 && src[len - dlen - 1] == '\\' &&
2117 !strcmp(src + len - dlen, fdat.cFileName)) {
2120 continue; /* ignore this one */
2122 filename = dupcat(srcpath, fdat.cFileName, NULL);
2125 } while (FindNextFile(dir, &fdat));
2132 * We will copy files from a remote server to the local machine.
2134 static void tolocal(int argc, char *argv[])
2136 char *src, *targ, *host, *user;
2140 bump("More than one remote source not supported");
2145 /* Separate host from filename */
2149 bump("Local to local copy not supported");
2153 /* Substitute "." for empty filename */
2155 /* Separate username and hostname */
2157 host = strrchr(host, '@');
2167 cmd = smalloc(strlen(src) + 100);
2168 sprintf(cmd, "scp%s%s%s%s -f %s",
2169 verbose ? " -v" : "",
2170 recursive ? " -r" : "",
2171 preserve ? " -p" : "",
2172 targetshouldbedirectory ? " -d" : "", src);
2173 do_cmd(host, user, cmd);
2176 if (scp_sink_setup(src, preserve, recursive))
2183 * We will issue a list command to get a remote directory.
2185 static void get_dir_list(int argc, char *argv[])
2187 char *src, *host, *user;
2193 /* Separate host from filename */
2197 bump("Local to local copy not supported");
2201 /* Substitute "." for empty filename */
2203 /* Separate username and hostname */
2205 host = strrchr(host, '@');
2215 cmd = smalloc(4 * strlen(src) + 100);
2216 strcpy(cmd, "ls -la '");
2217 p = cmd + strlen(cmd);
2218 for (q = src; *q; q++) {
2231 do_cmd(host, user, cmd);
2235 scp_sftp_listdir(src);
2237 while (ssh_scp_recv(&c, 1) > 0)
2238 tell_char(stdout, c);
2243 * Initialize the Win$ock driver.
2245 static void init_winsock(void)
2250 winsock_ver = MAKEWORD(1, 1);
2251 if (WSAStartup(winsock_ver, &wsadata))
2252 bump("Unable to initialise WinSock");
2253 if (LOBYTE(wsadata.wVersion) != 1 || HIBYTE(wsadata.wVersion) != 1)
2254 bump("WinSock version is incompatible with 1.1");
2258 * Short description of parameters.
2260 static void usage(void)
2262 printf("PuTTY Secure Copy client\n");
2263 printf("%s\n", ver);
2264 printf("Usage: pscp [options] [user@]host:source target\n");
2266 (" pscp [options] source [source...] [user@]host:target\n");
2267 printf(" pscp [options] -ls user@host:filespec\n");
2268 printf("Options:\n");
2269 printf(" -p preserve file attributes\n");
2270 printf(" -q quiet, don't show statistics\n");
2271 printf(" -r copy directories recursively\n");
2272 printf(" -v show verbose messages\n");
2273 printf(" -P port connect to specified port\n");
2274 printf(" -pw passw login with specified password\n");
2275 printf(" -unsafe allow server-side wildcards (DANGEROUS)\n");
2278 * -gui is an internal option, used by GUI front ends to get
2279 * pscp to pass progress reports back to them. It's not an
2280 * ordinary user-accessible option, so it shouldn't be part of
2281 * the command-line help. The only people who need to know
2282 * about it are programmers, and they can read the source.
2285 (" -gui hWnd GUI mode with the windows handle for receiving messages\n");
2291 * Main program (no, really?)
2293 int main(int argc, char *argv[])
2297 default_protocol = PROT_TELNET;
2299 flags = FLAG_STDERR;
2300 ssh_get_line = &get_line;
2304 for (i = 1; i < argc; i++) {
2305 if (argv[i][0] != '-')
2307 if (strcmp(argv[i], "-v") == 0)
2308 verbose = 1, flags |= FLAG_VERBOSE;
2309 else if (strcmp(argv[i], "-r") == 0)
2311 else if (strcmp(argv[i], "-p") == 0)
2313 else if (strcmp(argv[i], "-q") == 0)
2315 else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0)
2317 else if (strcmp(argv[i], "-P") == 0 && i + 1 < argc)
2318 portnumber = atoi(argv[++i]);
2319 else if (strcmp(argv[i], "-pw") == 0 && i + 1 < argc)
2320 password = argv[++i];
2321 else if (strcmp(argv[i], "-gui") == 0 && i + 1 < argc) {
2322 gui_hwnd = argv[++i];
2324 } else if (strcmp(argv[i], "-ls") == 0)
2326 else if (strcmp(argv[i], "-unsafe") == 0)
2327 scp_unsafe_mode = 1;
2328 else if (strcmp(argv[i], "--") == 0) {
2341 get_dir_list(argc, argv);
2348 targetshouldbedirectory = 1;
2350 if (colon(argv[argc - 1]) != NULL)
2351 toremote(argc, argv);
2353 tolocal(argc, argv);
2356 if (back != NULL && back->socket() != NULL) {
2358 back->special(TS_EOF);
2359 ssh_scp_recv(&ch, 1);
2364 /* GUI Adaptation - August 2000 */
2366 unsigned int msg_id = WM_RET_ERR_CNT;
2368 msg_id = WM_LS_RET_ERR_CNT;
2370 ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs,
2371 0 /*lParam */ ))SleepEx(1000, TRUE);
2373 return (errs == 0 ? 0 : 1);