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 * Adaptations to enable connecting a GUI by L. Gunnarsson - Sept 2000
26 #define PUTTY_DO_GLOBALS
33 #define TIME_POSIX_TO_WIN(t, ft) (*(LONGLONG*)&(ft) = \
34 ((LONGLONG) (t) + (LONGLONG) 11644473600) * (LONGLONG) 10000000)
35 #define TIME_WIN_TO_POSIX(ft, t) ((t) = (unsigned long) \
36 ((*(LONGLONG*)&(ft)) / (LONGLONG) 10000000 - (LONGLONG) 11644473600))
38 /* GUI Adaptation - Sept 2000 */
39 #define WM_APP_BASE 0x8000
40 #define WM_STD_OUT_CHAR ( WM_APP_BASE+400 )
41 #define WM_STD_ERR_CHAR ( WM_APP_BASE+401 )
42 #define WM_STATS_CHAR ( WM_APP_BASE+402 )
43 #define WM_STATS_SIZE ( WM_APP_BASE+403 )
44 #define WM_STATS_PERCENT ( WM_APP_BASE+404 )
45 #define WM_STATS_ELAPSED ( WM_APP_BASE+405 )
46 #define WM_RET_ERR_CNT ( WM_APP_BASE+406 )
47 #define WM_LS_RET_ERR_CNT ( WM_APP_BASE+407 )
50 static int verbose
= 0;
51 static int recursive
= 0;
52 static int preserve
= 0;
53 static int targetshouldbedirectory
= 0;
54 static int statistics
= 1;
55 static int portnumber
= 0;
56 static int prev_stats_len
= 0;
57 static int scp_unsafe_mode
= 0;
58 static char *password
= NULL
;
60 /* GUI Adaptation - Sept 2000 */
61 #define NAME_STR_MAX 2048
62 static char statname
[NAME_STR_MAX
+ 1];
63 static unsigned long statsize
= 0;
64 static int statperct
= 0;
65 static unsigned long statelapsed
= 0;
66 static int gui_mode
= 0;
67 static char *gui_hwnd
= NULL
;
68 static int using_sftp
= 0;
70 static void source(char *src
);
71 static void rsource(char *src
);
72 static void sink(char *targ
, char *src
);
73 /* GUI Adaptation - Sept 2000 */
74 static void tell_char(FILE * stream
, char c
);
75 static void tell_str(FILE * stream
, char *str
);
76 static void tell_user(FILE * stream
, char *fmt
, ...);
77 static void gui_update_stats(char *name
, unsigned long size
,
78 int percentage
, unsigned long elapsed
);
81 * The maximum amount of queued data we accept before we stop and
82 * wait for the server to process some.
84 #define MAX_SCP_BUFSIZE 16384
86 void logevent(char *string
)
90 void ldisc_send(char *buf
, int len
)
93 * This is only here because of the calls to ldisc_send(NULL,
94 * 0) in ssh.c. Nothing in PSCP actually needs to use the ldisc
95 * as an ldisc. So if we get called with any real data, I want
101 void verify_ssh_host_key(char *host
, int port
, char *keytype
,
102 char *keystr
, char *fingerprint
)
108 static const char absentmsg
[] =
109 "The server's host key is not cached in the registry. You\n"
110 "have no guarantee that the server is the computer you\n"
112 "The server's key fingerprint is:\n"
114 "If you trust this host, enter \"y\" to add the key to\n"
115 "PuTTY's cache and carry on connecting.\n"
116 "If you want to carry on connecting just once, without\n"
117 "adding the key to the cache, enter \"n\".\n"
118 "If you do not trust this host, press Return to abandon the\n"
120 "Store key in cache? (y/n) ";
122 static const char wrongmsg
[] =
123 "WARNING - POTENTIAL SECURITY BREACH!\n"
124 "The server's host key does not match the one PuTTY has\n"
125 "cached in the registry. This means that either the\n"
126 "server administrator has changed the host key, or you\n"
127 "have actually connected to another computer pretending\n"
128 "to be the server.\n"
129 "The new key fingerprint is:\n"
131 "If you were expecting this change and trust the new key,\n"
132 "enter \"y\" to update PuTTY's cache and continue connecting.\n"
133 "If you want to carry on connecting but without updating\n"
134 "the cache, enter \"n\".\n"
135 "If you want to abandon the connection completely, press\n"
136 "Return to cancel. Pressing Return is the ONLY guaranteed\n"
138 "Update cached key? (y/n, Return cancels connection) ";
140 static const char abandoned
[] = "Connection abandoned.\n";
145 * Verify the key against the registry.
147 ret
= verify_host_key(host
, port
, keytype
, keystr
);
149 if (ret
== 0) /* success - key matched OK */
152 if (ret
== 2) { /* key was different */
153 fprintf(stderr
, wrongmsg
, fingerprint
);
156 if (ret
== 1) { /* key was absent */
157 fprintf(stderr
, absentmsg
, fingerprint
);
161 hin
= GetStdHandle(STD_INPUT_HANDLE
);
162 GetConsoleMode(hin
, &savemode
);
163 SetConsoleMode(hin
, (savemode
| ENABLE_ECHO_INPUT
|
164 ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
));
165 ReadFile(hin
, line
, sizeof(line
) - 1, &i
, NULL
);
166 SetConsoleMode(hin
, savemode
);
168 if (line
[0] != '\0' && line
[0] != '\r' && line
[0] != '\n') {
169 if (line
[0] == 'y' || line
[0] == 'Y')
170 store_host_key(host
, port
, keytype
, keystr
);
172 fprintf(stderr
, abandoned
);
178 * Ask whether the selected cipher is acceptable (since it was
179 * below the configured 'warn' threshold).
180 * cs: 0 = both ways, 1 = client->server, 2 = server->client
182 void askcipher(char *ciphername
, int cs
)
187 static const char msg
[] =
188 "The first %scipher supported by the server is\n"
189 "%s, which is below the configured warning threshold.\n"
190 "Continue with connection? (y/n) ";
191 static const char abandoned
[] = "Connection abandoned.\n";
197 (cs
== 1) ?
"client-to-server " :
202 hin
= GetStdHandle(STD_INPUT_HANDLE
);
203 GetConsoleMode(hin
, &savemode
);
204 SetConsoleMode(hin
, (savemode
| ENABLE_ECHO_INPUT
|
205 ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
));
206 ReadFile(hin
, line
, sizeof(line
) - 1, &i
, NULL
);
207 SetConsoleMode(hin
, savemode
);
209 if (line
[0] == 'y' || line
[0] == 'Y') {
212 fprintf(stderr
, abandoned
);
217 /* GUI Adaptation - Sept 2000 */
218 static void send_msg(HWND h
, UINT message
, WPARAM wParam
)
220 while (!PostMessage(h
, message
, wParam
, 0))
224 static void tell_char(FILE * stream
, char c
)
229 unsigned int msg_id
= WM_STD_OUT_CHAR
;
230 if (stream
== stderr
)
231 msg_id
= WM_STD_ERR_CHAR
;
232 send_msg((HWND
) atoi(gui_hwnd
), msg_id
, (WPARAM
) c
);
236 static void tell_str(FILE * stream
, char *str
)
240 for (i
= 0; i
< strlen(str
); ++i
)
241 tell_char(stream
, str
[i
]);
244 static void tell_user(FILE * stream
, char *fmt
, ...)
246 char str
[0x100]; /* Make the size big enough */
249 vsprintf(str
, fmt
, ap
);
252 tell_str(stream
, str
);
255 static void gui_update_stats(char *name
, unsigned long size
,
256 int percentage
, unsigned long elapsed
)
260 if (strcmp(name
, statname
) != 0) {
261 for (i
= 0; i
< strlen(name
); ++i
)
262 send_msg((HWND
) atoi(gui_hwnd
), WM_STATS_CHAR
,
264 send_msg((HWND
) atoi(gui_hwnd
), WM_STATS_CHAR
, (WPARAM
) '\n');
265 strcpy(statname
, name
);
267 if (statsize
!= size
) {
268 send_msg((HWND
) atoi(gui_hwnd
), WM_STATS_SIZE
, (WPARAM
) size
);
271 if (statelapsed
!= elapsed
) {
272 send_msg((HWND
) atoi(gui_hwnd
), WM_STATS_ELAPSED
,
274 statelapsed
= elapsed
;
276 if (statperct
!= percentage
) {
277 send_msg((HWND
) atoi(gui_hwnd
), WM_STATS_PERCENT
,
278 (WPARAM
) percentage
);
279 statperct
= percentage
;
284 * Print an error message and perform a fatal exit.
286 void fatalbox(char *fmt
, ...)
288 char str
[0x100]; /* Make the size big enough */
291 strcpy(str
, "Fatal: ");
292 vsprintf(str
+ strlen(str
), fmt
, ap
);
295 tell_str(stderr
, str
);
299 unsigned int msg_id
= WM_RET_ERR_CNT
;
301 msg_id
= WM_LS_RET_ERR_CNT
;
303 ((HWND
) atoi(gui_hwnd
), msg_id
, (WPARAM
) errs
,
304 0 /*lParam */ ))SleepEx(1000, TRUE
);
309 void connection_fatal(char *fmt
, ...)
311 char str
[0x100]; /* Make the size big enough */
314 strcpy(str
, "Fatal: ");
315 vsprintf(str
+ strlen(str
), fmt
, ap
);
318 tell_str(stderr
, str
);
322 unsigned int msg_id
= WM_RET_ERR_CNT
;
324 msg_id
= WM_LS_RET_ERR_CNT
;
326 ((HWND
) atoi(gui_hwnd
), msg_id
, (WPARAM
) errs
,
327 0 /*lParam */ ))SleepEx(1000, TRUE
);
334 * Be told what socket we're supposed to be using.
336 static SOCKET scp_ssh_socket
;
337 char *do_select(SOCKET skt
, int startup
)
340 scp_ssh_socket
= skt
;
342 scp_ssh_socket
= INVALID_SOCKET
;
345 extern int select_result(WPARAM
, LPARAM
);
348 * Receive a block of data from the SSH link. Block until all data
351 * To do this, we repeatedly call the SSH protocol module, with our
352 * own trap in from_backend() to catch the data that comes back. We
353 * do this until we have enough data.
356 static unsigned char *outptr
; /* where to put the data */
357 static unsigned outlen
; /* how much data required */
358 static unsigned char *pending
= NULL
; /* any spare data */
359 static unsigned pendlen
= 0, pendsize
= 0; /* length and phys. size of buffer */
360 int from_backend(int is_stderr
, char *data
, int datalen
)
362 unsigned char *p
= (unsigned char *) data
;
363 unsigned len
= (unsigned) datalen
;
366 * stderr data is just spouted to local stderr and otherwise
370 fwrite(data
, 1, len
, stderr
);
377 * If this is before the real session begins, just return.
383 unsigned used
= outlen
;
386 memcpy(outptr
, p
, used
);
394 if (pendsize
< pendlen
+ len
) {
395 pendsize
= pendlen
+ len
+ 4096;
396 pending
= (pending ?
srealloc(pending
, pendsize
) :
399 fatalbox("Out of memory");
401 memcpy(pending
+ pendlen
, p
, len
);
407 static int scp_process_network_event(void)
412 FD_SET(scp_ssh_socket
, &readfds
);
413 if (select(1, &readfds
, NULL
, NULL
, NULL
) < 0)
415 select_result((WPARAM
) scp_ssh_socket
, (LPARAM
) FD_READ
);
418 static int ssh_scp_recv(unsigned char *buf
, int len
)
424 * See if the pending-input block contains some of what we
428 unsigned pendused
= pendlen
;
429 if (pendused
> outlen
)
431 memcpy(outptr
, pending
, pendused
);
432 memmove(pending
, pending
+ pendused
, pendlen
- pendused
);
446 if (!scp_process_network_event())
454 * Loop through the ssh connection and authentication process.
456 static void ssh_scp_init(void)
458 if (scp_ssh_socket
== INVALID_SOCKET
)
460 while (!back
->sendok()) {
463 FD_SET(scp_ssh_socket
, &readfds
);
464 if (select(1, &readfds
, NULL
, NULL
, NULL
) < 0)
466 select_result((WPARAM
) scp_ssh_socket
, (LPARAM
) FD_READ
);
468 using_sftp
= !ssh_fallback_cmd
;
472 * Print an error message and exit after closing the SSH link.
474 static void bump(char *fmt
, ...)
476 char str
[0x100]; /* Make the size big enough */
479 strcpy(str
, "Fatal: ");
480 vsprintf(str
+ strlen(str
), fmt
, ap
);
483 tell_str(stderr
, str
);
486 if (back
!= NULL
&& back
->socket() != NULL
) {
488 back
->special(TS_EOF
);
489 ssh_scp_recv(&ch
, 1);
493 unsigned int msg_id
= WM_RET_ERR_CNT
;
495 msg_id
= WM_LS_RET_ERR_CNT
;
497 ((HWND
) atoi(gui_hwnd
), msg_id
, (WPARAM
) errs
,
498 0 /*lParam */ ))SleepEx(1000, TRUE
);
504 static int get_line(const char *prompt
, char *str
, int maxlen
, int is_pw
)
507 DWORD savemode
, newmode
, i
;
509 if (is_pw
&& password
) {
510 static int tried_once
= 0;
515 strncpy(str
, password
, maxlen
);
516 str
[maxlen
- 1] = '\0';
522 /* GUI Adaptation - Sept 2000 */
527 hin
= GetStdHandle(STD_INPUT_HANDLE
);
528 hout
= GetStdHandle(STD_OUTPUT_HANDLE
);
529 if (hin
== INVALID_HANDLE_VALUE
|| hout
== INVALID_HANDLE_VALUE
)
530 bump("Cannot get standard input/output handles");
532 GetConsoleMode(hin
, &savemode
);
533 newmode
= savemode
| ENABLE_PROCESSED_INPUT
| ENABLE_LINE_INPUT
;
535 newmode
&= ~ENABLE_ECHO_INPUT
;
537 newmode
|= ENABLE_ECHO_INPUT
;
538 SetConsoleMode(hin
, newmode
);
540 WriteFile(hout
, prompt
, strlen(prompt
), &i
, NULL
);
541 ReadFile(hin
, str
, maxlen
- 1, &i
, NULL
);
543 SetConsoleMode(hin
, savemode
);
545 if ((int) i
> maxlen
)
552 WriteFile(hout
, "\r\n", 2, &i
, NULL
);
559 * Open an SSH connection to user@host and execute cmd.
561 static void do_cmd(char *host
, char *user
, char *cmd
)
563 char *err
, *realhost
;
566 if (host
== NULL
|| host
[0] == '\0')
567 bump("Empty host name");
569 /* Try to load settings for this host */
570 do_defaults(host
, &cfg
);
571 if (cfg
.host
[0] == '\0') {
572 /* No settings for this host; use defaults */
573 do_defaults(NULL
, &cfg
);
574 strncpy(cfg
.host
, host
, sizeof(cfg
.host
) - 1);
575 cfg
.host
[sizeof(cfg
.host
) - 1] = '\0';
580 if (user
!= NULL
&& user
[0] != '\0') {
581 strncpy(cfg
.username
, user
, sizeof(cfg
.username
) - 1);
582 cfg
.username
[sizeof(cfg
.username
) - 1] = '\0';
583 } else if (cfg
.username
[0] == '\0') {
585 if (GetUserName(user
, &namelen
) == FALSE
)
586 bump("Empty user name");
587 user
= smalloc(namelen
* sizeof(char));
588 GetUserName(user
, &namelen
);
590 tell_user(stderr
, "Guessing user name: %s", user
);
591 strncpy(cfg
.username
, user
, sizeof(cfg
.username
) - 1);
592 cfg
.username
[sizeof(cfg
.username
) - 1] = '\0';
596 if (cfg
.protocol
!= PROT_SSH
)
600 cfg
.port
= portnumber
;
603 * Attempt to start the SFTP subsystem as a first choice,
604 * falling back to the provided scp command if that fails.
606 strcpy(cfg
.remote_cmd
, "sftp");
607 cfg
.ssh_subsys
= TRUE
;
608 cfg
.remote_cmd_ptr2
= cmd
;
609 cfg
.ssh_subsys2
= FALSE
;
614 err
= back
->init(cfg
.host
, cfg
.port
, &realhost
);
616 bump("ssh_init: %s", err
);
618 if (verbose
&& realhost
!= NULL
)
619 tell_user(stderr
, "Connected to %s\n", realhost
);
624 * Update statistic information about current file.
626 static void print_stats(char *name
, unsigned long size
, unsigned long done
,
627 time_t start
, time_t now
)
635 /* GUI Adaptation - Sept 2000 */
637 gui_update_stats(name
, size
, (int) (100 * (done
* 1.0 / size
)),
638 (unsigned long) difftime(now
, start
));
641 ratebs
= (float) done
/ (now
- start
);
643 ratebs
= (float) done
;
648 eta
= (unsigned long) ((size
- done
) / ratebs
);
649 sprintf(etastr
, "%02ld:%02ld:%02ld",
650 eta
/ 3600, (eta
% 3600) / 60, eta
% 60);
652 pct
= (int) (100 * (done
* 1.0 / size
));
654 len
= printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%",
655 name
, done
/ 1024, ratebs
/ 1024.0, etastr
, pct
);
656 if (len
< prev_stats_len
)
657 printf("%*s", prev_stats_len
- len
, "");
658 prev_stats_len
= len
;
666 * Find a colon in str and return a pointer to the colon.
667 * This is used to separate hostname from filename.
669 static char *colon(char *str
)
671 /* We ignore a leading colon, since the hostname cannot be
672 empty. We also ignore a colon as second character because
673 of filenames like f:myfile.txt. */
674 if (str
[0] == '\0' || str
[0] == ':' || str
[1] == ':')
676 while (*str
!= '\0' && *str
!= ':' && *str
!= '/' && *str
!= '\\')
685 * Return a pointer to the portion of str that comes after the last
686 * slash (or backslash or colon, if `local' is TRUE).
688 static char *stripslashes(char *str
, int local
)
693 p
= strchr(str
, ':');
697 p
= strrchr(str
, '/');
701 p
= strrchr(str
, '\\');
709 * Determine whether a string is entirely composed of dots.
711 static int is_dots(char *str
)
713 return str
[strspn(str
, ".")] == '\0';
717 * Wait for a response from the other side.
718 * Return 0 if ok, -1 if error.
720 static int response(void)
722 char ch
, resp
, rbuf
[2048];
725 if (ssh_scp_recv(&resp
, 1) <= 0)
726 bump("Lost connection");
736 case 2: /* fatal error */
738 if (ssh_scp_recv(&ch
, 1) <= 0)
739 bump("Protocol error: Lost connection");
741 } while (p
< sizeof(rbuf
) && ch
!= '\n');
744 tell_user(stderr
, "%s\n", rbuf
);
752 int sftp_recvdata(char *buf
, int len
)
754 return ssh_scp_recv(buf
, len
);
756 int sftp_senddata(char *buf
, int len
)
758 back
->send((unsigned char *) buf
, len
);
762 /* ----------------------------------------------------------------------
763 * sftp-based replacement for the hacky `pscp -ls'.
765 static int sftp_ls_compare(const void *av
, const void *bv
)
767 const struct fxp_name
*a
= (const struct fxp_name
*) av
;
768 const struct fxp_name
*b
= (const struct fxp_name
*) bv
;
769 return strcmp(a
->filename
, b
->filename
);
771 void scp_sftp_listdir(char *dirname
)
773 struct fxp_handle
*dirh
;
774 struct fxp_names
*names
;
775 struct fxp_name
*ournames
;
776 int nnames
, namesize
;
779 printf("Listing directory %s\n", dirname
);
781 dirh
= fxp_opendir(dirname
);
783 printf("Unable to open %s: %s\n", dirname
, fxp_error());
785 nnames
= namesize
= 0;
790 names
= fxp_readdir(dirh
);
792 if (fxp_error_type() == SSH_FX_EOF
)
794 printf("Reading directory %s: %s\n", dirname
, fxp_error());
797 if (names
->nnames
== 0) {
798 fxp_free_names(names
);
802 if (nnames
+ names
->nnames
>= namesize
) {
803 namesize
+= names
->nnames
+ 128;
805 srealloc(ournames
, namesize
* sizeof(*ournames
));
808 for (i
= 0; i
< names
->nnames
; i
++)
809 ournames
[nnames
++] = names
->names
[i
];
811 names
->nnames
= 0; /* prevent free_names */
812 fxp_free_names(names
);
817 * Now we have our filenames. Sort them by actual file
818 * name, and then output the longname parts.
820 qsort(ournames
, nnames
, sizeof(*ournames
), sftp_ls_compare
);
825 for (i
= 0; i
< nnames
; i
++)
826 printf("%s\n", ournames
[i
].longname
);
830 /* ----------------------------------------------------------------------
831 * Helper routines that contain the actual SCP protocol elements,
832 * implemented both as SCP1 and SFTP.
835 static struct scp_sftp_dirstack
{
836 struct scp_sftp_dirstack
*next
;
837 struct fxp_name
*names
;
838 int namepos
, namelen
;
841 int matched_something
; /* wildcard match set was non-empty */
842 } *scp_sftp_dirstack_head
;
843 static char *scp_sftp_remotepath
, *scp_sftp_currentname
;
844 static char *scp_sftp_wildcard
;
845 static int scp_sftp_targetisdir
, scp_sftp_donethistarget
;
846 static int scp_sftp_preserve
, scp_sftp_recursive
;
847 static unsigned long scp_sftp_mtime
, scp_sftp_atime
;
848 static int scp_has_times
;
849 static struct fxp_handle
*scp_sftp_filehandle
;
850 static uint64 scp_sftp_fileoffset
;
852 void scp_source_setup(char *target
, int shouldbedir
)
856 * Find out whether the target filespec is in fact a
859 struct fxp_attrs attrs
;
861 if (!fxp_stat(target
, &attrs
) ||
862 !(attrs
.flags
& SSH_FILEXFER_ATTR_PERMISSIONS
))
863 scp_sftp_targetisdir
= 0;
865 scp_sftp_targetisdir
= (attrs
.permissions
& 0040000) != 0;
867 if (shouldbedir
&& !scp_sftp_targetisdir
) {
868 bump("pscp: remote filespec %s: not a directory\n", target
);
871 scp_sftp_remotepath
= dupstr(target
);
879 int scp_send_errmsg(char *str
)
882 /* do nothing; we never need to send our errors to the server */
884 back
->send("\001", 1); /* scp protocol error prefix */
885 back
->send(str
, strlen(str
));
887 return 0; /* can't fail */
890 int scp_send_filetimes(unsigned long mtime
, unsigned long atime
)
893 scp_sftp_mtime
= mtime
;
894 scp_sftp_atime
= atime
;
899 sprintf(buf
, "T%lu 0 %lu 0\n", mtime
, atime
);
900 back
->send(buf
, strlen(buf
));
905 int scp_send_filename(char *name
, unsigned long size
, int modes
)
909 if (scp_sftp_targetisdir
) {
910 fullname
= dupcat(scp_sftp_remotepath
, "/", name
, NULL
);
912 fullname
= dupstr(scp_sftp_remotepath
);
914 scp_sftp_filehandle
=
915 fxp_open(fullname
, SSH_FXF_WRITE
| SSH_FXF_CREAT
| SSH_FXF_TRUNC
);
916 if (!scp_sftp_filehandle
) {
917 tell_user(stderr
, "pscp: unable to open %s: %s",
918 fullname
, fxp_error());
922 scp_sftp_fileoffset
= uint64_make(0, 0);
927 sprintf(buf
, "C%04o %lu ", modes
, size
);
928 back
->send(buf
, strlen(buf
));
929 back
->send(name
, strlen(name
));
935 int scp_send_filedata(char *data
, int len
)
938 if (!scp_sftp_filehandle
) {
941 if (!fxp_write(scp_sftp_filehandle
, data
, scp_sftp_fileoffset
, len
)) {
942 tell_user(stderr
, "error while writing: %s\n", fxp_error());
946 scp_sftp_fileoffset
= uint64_add32(scp_sftp_fileoffset
, len
);
949 int bufsize
= back
->send(data
, len
);
952 * If the network transfer is backing up - that is, the
953 * remote site is not accepting data as fast as we can
954 * produce it - then we must loop on network events until
955 * we have space in the buffer again.
957 while (bufsize
> MAX_SCP_BUFSIZE
) {
958 if (!scp_process_network_event())
960 bufsize
= back
->sendbuffer();
967 int scp_send_finish(void)
970 struct fxp_attrs attrs
;
971 if (!scp_sftp_filehandle
) {
975 attrs
.flags
= SSH_FILEXFER_ATTR_ACMODTIME
;
976 attrs
.atime
= scp_sftp_atime
;
977 attrs
.mtime
= scp_sftp_mtime
;
978 if (!fxp_fsetstat(scp_sftp_filehandle
, attrs
)) {
979 tell_user(stderr
, "unable to set file times: %s\n", fxp_error());
983 fxp_close(scp_sftp_filehandle
);
992 char *scp_save_remotepath(void)
995 return scp_sftp_remotepath
;
1000 void scp_restore_remotepath(char *data
)
1003 scp_sftp_remotepath
= data
;
1006 int scp_send_dirname(char *name
, int modes
)
1011 struct fxp_attrs attrs
;
1012 if (scp_sftp_targetisdir
) {
1013 fullname
= dupcat(scp_sftp_remotepath
, "/", name
, NULL
);
1015 fullname
= dupstr(scp_sftp_remotepath
);
1019 * We don't worry about whether we managed to create the
1020 * directory, because if it exists already it's OK just to
1021 * use it. Instead, we will stat it afterwards, and if it
1022 * exists and is a directory we will assume we were either
1023 * successful or it didn't matter.
1025 if (!fxp_mkdir(fullname
))
1028 err
= "server reported no error";
1029 if (!fxp_stat(fullname
, &attrs
) ||
1030 !(attrs
.flags
& SSH_FILEXFER_ATTR_PERMISSIONS
) ||
1031 !(attrs
.permissions
& 0040000)) {
1032 tell_user(stderr
, "unable to create directory %s: %s",
1038 scp_sftp_remotepath
= fullname
;
1043 sprintf(buf
, "D%04o 0 ", modes
);
1044 back
->send(buf
, strlen(buf
));
1045 back
->send(name
, strlen(name
));
1046 back
->send("\n", 1);
1051 int scp_send_enddir(void)
1054 sfree(scp_sftp_remotepath
);
1057 back
->send("E\n", 2);
1063 * Yes, I know; I have an scp_sink_setup _and_ an scp_sink_init.
1064 * That's bad. The difference is that scp_sink_setup is called once
1065 * right at the start, whereas scp_sink_init is called to
1066 * initialise every level of recursion in the protocol.
1068 int scp_sink_setup(char *source
, int preserve
, int recursive
)
1073 * It's possible that the source string we've been given
1074 * contains a wildcard. If so, we must split the directory
1075 * away from the wildcard itself (throwing an error if any
1076 * wildcardness comes before the final slash) and arrange
1077 * things so that a dirstack entry will be set up.
1079 newsource
= smalloc(1+strlen(source
));
1080 if (!wc_unescape(newsource
, source
)) {
1081 /* Yes, here we go; it's a wildcard. Bah. */
1082 char *dupsource
, *lastpart
, *dirpart
, *wildcard
;
1083 dupsource
= dupstr(source
);
1084 lastpart
= stripslashes(dupsource
, 0);
1085 wildcard
= dupstr(lastpart
);
1087 if (*dupsource
&& dupsource
[1]) {
1089 * The remains of dupsource are at least two
1090 * characters long, meaning the pathname wasn't
1091 * empty or just `/'. Hence, we remove the trailing
1094 lastpart
[-1] = '\0';
1095 } else if (!*dupsource
) {
1097 * The remains of dupsource are _empty_ - the whole
1098 * pathname was a wildcard. Hence we need to
1099 * replace it with ".".
1102 dupsource
= dupstr(".");
1106 * Now we have separated our string into dupsource (the
1107 * directory part) and wildcard. Both of these will
1108 * need freeing at some point. Next step is to remove
1109 * wildcard escapes from the directory part, throwing
1110 * an error if it contains a real wildcard.
1112 dirpart
= smalloc(1+strlen(dupsource
));
1113 if (!wc_unescape(dirpart
, dupsource
)) {
1114 tell_user(stderr
, "%s: multiple-level wildcards unsupported",
1124 * Now we have dirpart (unescaped, ie a valid remote
1125 * path), and wildcard (a wildcard). This will be
1126 * sufficient to arrange a dirstack entry.
1128 scp_sftp_remotepath
= dirpart
;
1129 scp_sftp_wildcard
= wildcard
;
1132 scp_sftp_remotepath
= newsource
;
1133 scp_sftp_wildcard
= NULL
;
1135 scp_sftp_preserve
= preserve
;
1136 scp_sftp_recursive
= recursive
;
1137 scp_sftp_donethistarget
= 0;
1138 scp_sftp_dirstack_head
= NULL
;
1143 int scp_sink_init(void)
1151 #define SCP_SINK_FILE 1
1152 #define SCP_SINK_DIR 2
1153 #define SCP_SINK_ENDDIR 3
1154 #define SCP_SINK_RETRY 4 /* not an action; just try again */
1155 struct scp_sink_action
{
1156 int action
; /* FILE, DIR, ENDDIR */
1157 char *buf
; /* will need freeing after use */
1158 char *name
; /* filename or dirname (not ENDDIR) */
1159 int mode
; /* access mode (not ENDDIR) */
1160 unsigned long size
; /* file size (not ENDDIR) */
1161 int settime
; /* 1 if atime and mtime are filled */
1162 unsigned long atime
, mtime
; /* access times for the file */
1165 int scp_get_sink_action(struct scp_sink_action
*act
)
1169 int must_free_fname
;
1170 struct fxp_attrs attrs
;
1173 if (!scp_sftp_dirstack_head
) {
1174 if (!scp_sftp_donethistarget
) {
1176 * Simple case: we are only dealing with one file.
1178 fname
= scp_sftp_remotepath
;
1179 must_free_fname
= 0;
1180 scp_sftp_donethistarget
= 1;
1183 * Even simpler case: one file _which we've done_.
1184 * Return 1 (finished).
1190 * We're now in the middle of stepping through a list
1191 * of names returned from fxp_readdir(); so let's carry
1194 struct scp_sftp_dirstack
*head
= scp_sftp_dirstack_head
;
1195 while (head
->namepos
< head
->namelen
&&
1196 (is_dots(head
->names
[head
->namepos
].filename
) ||
1198 !wc_match(head
->wildcard
,
1199 head
->names
[head
->namepos
].filename
))))
1200 head
->namepos
++; /* skip . and .. */
1201 if (head
->namepos
< head
->namelen
) {
1202 head
->matched_something
= 1;
1203 fname
= dupcat(head
->dirpath
, "/",
1204 head
->names
[head
->namepos
++].filename
,
1206 must_free_fname
= 1;
1209 * We've come to the end of the list; pop it off
1210 * the stack and return an ENDDIR action (or RETRY
1211 * if this was a wildcard match).
1213 if (head
->wildcard
) {
1214 act
->action
= SCP_SINK_RETRY
;
1215 if (!head
->matched_something
) {
1216 tell_user(stderr
, "pscp: wildcard '%s' matched "
1217 "no files", head
->wildcard
);
1220 sfree(head
->wildcard
);
1223 act
->action
= SCP_SINK_ENDDIR
;
1226 sfree(head
->dirpath
);
1228 scp_sftp_dirstack_head
= head
->next
;
1236 * Now we have a filename. Stat it, and see if it's a file
1239 ret
= fxp_stat(fname
, &attrs
);
1240 if (!ret
|| !(attrs
.flags
& SSH_FILEXFER_ATTR_PERMISSIONS
)) {
1241 tell_user(stderr
, "unable to identify %s: %s", fname
,
1242 ret ?
"file type not supplied" : fxp_error());
1247 if (attrs
.permissions
& 0040000) {
1248 struct scp_sftp_dirstack
*newitem
;
1249 struct fxp_handle
*dirhandle
;
1250 int nnames
, namesize
;
1251 struct fxp_name
*ournames
;
1252 struct fxp_names
*names
;
1255 * It's a directory. If we're not in recursive mode,
1256 * this merits a complaint (which is fatal if the name
1257 * was specified directly, but not if it was matched by
1260 * We skip this complaint completely if
1261 * scp_sftp_wildcard is set, because that's an
1262 * indication that we're not actually supposed to
1263 * _recursively_ transfer the dir, just scan it for
1264 * things matching the wildcard.
1266 if (!scp_sftp_recursive
&& !scp_sftp_wildcard
) {
1267 tell_user(stderr
, "pscp: %s: is a directory", fname
);
1269 if (must_free_fname
) sfree(fname
);
1270 if (scp_sftp_dirstack_head
) {
1271 act
->action
= SCP_SINK_RETRY
;
1279 * Otherwise, the fun begins. We must fxp_opendir() the
1280 * directory, slurp the filenames into memory, return
1281 * SCP_SINK_DIR (unless this is a wildcard match), and
1282 * set targetisdir. The next time we're called, we will
1283 * run through the list of filenames one by one,
1284 * matching them against a wildcard if present.
1286 * If targetisdir is _already_ set (meaning we're
1287 * already in the middle of going through another such
1288 * list), we must push the other (target,namelist) pair
1291 dirhandle
= fxp_opendir(fname
);
1293 tell_user(stderr
, "scp: unable to open directory %s: %s",
1294 fname
, fxp_error());
1295 if (must_free_fname
) sfree(fname
);
1299 nnames
= namesize
= 0;
1304 names
= fxp_readdir(dirhandle
);
1305 if (names
== NULL
) {
1306 if (fxp_error_type() == SSH_FX_EOF
)
1308 tell_user(stderr
, "scp: reading directory %s: %s\n",
1309 fname
, fxp_error());
1310 if (must_free_fname
) sfree(fname
);
1315 if (names
->nnames
== 0) {
1316 fxp_free_names(names
);
1319 if (nnames
+ names
->nnames
>= namesize
) {
1320 namesize
+= names
->nnames
+ 128;
1322 srealloc(ournames
, namesize
* sizeof(*ournames
));
1324 for (i
= 0; i
< names
->nnames
; i
++)
1325 ournames
[nnames
++] = names
->names
[i
];
1326 names
->nnames
= 0; /* prevent free_names */
1327 fxp_free_names(names
);
1329 fxp_close(dirhandle
);
1331 newitem
= smalloc(sizeof(struct scp_sftp_dirstack
));
1332 newitem
->next
= scp_sftp_dirstack_head
;
1333 newitem
->names
= ournames
;
1334 newitem
->namepos
= 0;
1335 newitem
->namelen
= nnames
;
1336 if (must_free_fname
)
1337 newitem
->dirpath
= fname
;
1339 newitem
->dirpath
= dupstr(fname
);
1340 if (scp_sftp_wildcard
) {
1341 newitem
->wildcard
= scp_sftp_wildcard
;
1342 newitem
->matched_something
= 0;
1343 scp_sftp_wildcard
= NULL
;
1345 newitem
->wildcard
= NULL
;
1347 scp_sftp_dirstack_head
= newitem
;
1349 if (newitem
->wildcard
) {
1350 act
->action
= SCP_SINK_RETRY
;
1352 act
->action
= SCP_SINK_DIR
;
1353 act
->buf
= dupstr(stripslashes(fname
, 0));
1354 act
->name
= act
->buf
;
1355 act
->size
= 0; /* duhh, it's a directory */
1356 act
->mode
= 07777 & attrs
.permissions
;
1357 if (scp_sftp_preserve
&&
1358 (attrs
.flags
& SSH_FILEXFER_ATTR_ACMODTIME
)) {
1359 act
->atime
= attrs
.atime
;
1360 act
->mtime
= attrs
.mtime
;
1369 * It's a file. Return SCP_SINK_FILE.
1371 act
->action
= SCP_SINK_FILE
;
1372 act
->buf
= dupstr(stripslashes(fname
, 0));
1373 act
->name
= act
->buf
;
1374 if (attrs
.flags
& SSH_FILEXFER_ATTR_SIZE
) {
1375 if (uint64_compare(attrs
.size
,
1376 uint64_make(0, ULONG_MAX
)) > 0) {
1377 act
->size
= ULONG_MAX
; /* *boggle* */
1379 act
->size
= attrs
.size
.lo
;
1381 act
->size
= ULONG_MAX
; /* no idea */
1382 act
->mode
= 07777 & attrs
.permissions
;
1383 if (scp_sftp_preserve
&&
1384 (attrs
.flags
& SSH_FILEXFER_ATTR_ACMODTIME
)) {
1385 act
->atime
= attrs
.atime
;
1386 act
->mtime
= attrs
.mtime
;
1390 if (must_free_fname
)
1391 scp_sftp_currentname
= fname
;
1393 scp_sftp_currentname
= dupstr(fname
);
1408 if (ssh_scp_recv(&ch
, 1) <= 0)
1411 bump("Protocol error: Unexpected newline");
1415 if (ssh_scp_recv(&ch
, 1) <= 0)
1416 bump("Lost connection");
1419 act
->buf
= srealloc(act
->buf
, bufsize
);
1422 } while (ch
!= '\n');
1423 act
->buf
[i
- 1] = '\0';
1425 case '\01': /* error */
1426 tell_user(stderr
, "%s\n", act
->buf
);
1428 continue; /* go round again */
1429 case '\02': /* fatal error */
1430 bump("%s", act
->buf
);
1433 act
->action
= SCP_SINK_ENDDIR
;
1436 if (sscanf(act
->buf
, "%ld %*d %ld %*d",
1437 &act
->mtime
, &act
->atime
) == 2) {
1440 continue; /* go round again */
1442 bump("Protocol error: Illegal time format");
1445 act
->action
= (action
== 'C' ? SCP_SINK_FILE
: SCP_SINK_DIR
);
1448 bump("Protocol error: Expected control record");
1451 * We will go round this loop only once, unless we hit
1458 * If we get here, we must have seen SCP_SINK_FILE or
1461 if (sscanf(act
->buf
, "%o %lu %n", &act
->mode
, &act
->size
, &i
) != 2)
1462 bump("Protocol error: Illegal file descriptor format");
1463 act
->name
= act
->buf
+ i
;
1468 int scp_accept_filexfer(void)
1471 scp_sftp_filehandle
=
1472 fxp_open(scp_sftp_currentname
, SSH_FXF_READ
);
1473 if (!scp_sftp_filehandle
) {
1474 tell_user(stderr
, "pscp: unable to open %s: %s",
1475 scp_sftp_currentname
, fxp_error());
1479 scp_sftp_fileoffset
= uint64_make(0, 0);
1480 sfree(scp_sftp_currentname
);
1484 return 0; /* can't fail */
1488 int scp_recv_filedata(char *data
, int len
)
1491 int actuallen
= fxp_read(scp_sftp_filehandle
, data
,
1492 scp_sftp_fileoffset
, len
);
1493 if (actuallen
== -1 && fxp_error_type() != SSH_FX_EOF
) {
1494 tell_user(stderr
, "pscp: error while reading: %s", fxp_error());
1501 scp_sftp_fileoffset
= uint64_add32(scp_sftp_fileoffset
, actuallen
);
1505 return ssh_scp_recv(data
, len
);
1509 int scp_finish_filerecv(void)
1512 fxp_close(scp_sftp_filehandle
);
1520 /* ----------------------------------------------------------------------
1521 * Send an error message to the other side and to the screen.
1522 * Increment error counter.
1524 static void run_err(const char *fmt
, ...)
1530 strcpy(str
, "scp: ");
1531 vsprintf(str
+ strlen(str
), fmt
, ap
);
1533 scp_send_errmsg(str
);
1534 tell_user(stderr
, "%s", str
);
1539 * Execute the source part of the SCP protocol.
1541 static void source(char *src
)
1548 unsigned long stat_bytes
;
1549 time_t stat_starttime
, stat_lasttime
;
1551 attr
= GetFileAttributes(src
);
1552 if (attr
== (DWORD
) - 1) {
1553 run_err("%s: No such file or directory", src
);
1557 if ((attr
& FILE_ATTRIBUTE_DIRECTORY
) != 0) {
1560 * Avoid . and .. directories.
1563 p
= strrchr(src
, '/');
1565 p
= strrchr(src
, '\\');
1570 if (!strcmp(p
, ".") || !strcmp(p
, ".."))
1571 /* skip . and .. */ ;
1575 run_err("%s: not a regular file", src
);
1580 if ((last
= strrchr(src
, '/')) == NULL
)
1584 if (strrchr(last
, '\\') != NULL
)
1585 last
= strrchr(last
, '\\') + 1;
1586 if (last
== src
&& strchr(src
, ':') != NULL
)
1587 last
= strchr(src
, ':') + 1;
1589 f
= CreateFile(src
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
1590 OPEN_EXISTING
, 0, 0);
1591 if (f
== INVALID_HANDLE_VALUE
) {
1592 run_err("%s: Cannot open file", src
);
1597 FILETIME actime
, wrtime
;
1598 unsigned long mtime
, atime
;
1599 GetFileTime(f
, NULL
, &actime
, &wrtime
);
1600 TIME_WIN_TO_POSIX(actime
, atime
);
1601 TIME_WIN_TO_POSIX(wrtime
, mtime
);
1602 if (scp_send_filetimes(mtime
, atime
))
1606 size
= GetFileSize(f
, NULL
);
1608 tell_user(stderr
, "Sending file %s, size=%lu", last
, size
);
1609 if (scp_send_filename(last
, size
, 0644))
1613 stat_starttime
= time(NULL
);
1616 for (i
= 0; i
< size
; i
+= 4096) {
1617 char transbuf
[4096];
1622 if (!ReadFile(f
, transbuf
, k
, &j
, NULL
) || j
!= k
) {
1625 bump("%s: Read error", src
);
1627 if (scp_send_filedata(transbuf
, k
))
1628 bump("%s: Network error occurred", src
);
1632 if (time(NULL
) != stat_lasttime
|| i
+ k
== size
) {
1633 stat_lasttime
= time(NULL
);
1634 print_stats(last
, size
, stat_bytes
,
1635 stat_starttime
, stat_lasttime
);
1642 (void) scp_send_finish();
1646 * Recursively send the contents of a directory.
1648 static void rsource(char *src
)
1650 char *last
, *findfile
;
1653 WIN32_FIND_DATA fdat
;
1656 if ((last
= strrchr(src
, '/')) == NULL
)
1660 if (strrchr(last
, '\\') != NULL
)
1661 last
= strrchr(last
, '\\') + 1;
1662 if (last
== src
&& strchr(src
, ':') != NULL
)
1663 last
= strchr(src
, ':') + 1;
1665 /* maybe send filetime */
1667 save_target
= scp_save_remotepath();
1670 tell_user(stderr
, "Entering directory: %s", last
);
1671 if (scp_send_dirname(last
, 0755))
1674 findfile
= dupcat(src
, "/*", NULL
);
1675 dir
= FindFirstFile(findfile
, &fdat
);
1676 ok
= (dir
!= INVALID_HANDLE_VALUE
);
1678 if (strcmp(fdat
.cFileName
, ".") == 0 ||
1679 strcmp(fdat
.cFileName
, "..") == 0) {
1680 /* ignore . and .. */
1682 char *foundfile
= dupcat(src
, "/", fdat
.cFileName
, NULL
);
1686 ok
= FindNextFile(dir
, &fdat
);
1691 (void) scp_send_enddir();
1693 scp_restore_remotepath(save_target
);
1697 * Execute the sink part of the SCP protocol.
1699 static void sink(char *targ
, char *src
)
1706 unsigned long received
;
1708 unsigned long stat_bytes
;
1709 time_t stat_starttime
, stat_lasttime
;
1712 attr
= GetFileAttributes(targ
);
1713 if (attr
!= (DWORD
) - 1 && (attr
& FILE_ATTRIBUTE_DIRECTORY
) != 0)
1716 if (targetshouldbedirectory
&& !targisdir
)
1717 bump("%s: Not a directory", targ
);
1721 struct scp_sink_action act
;
1722 if (scp_get_sink_action(&act
))
1725 if (act
.action
== SCP_SINK_ENDDIR
)
1728 if (act
.action
== SCP_SINK_RETRY
)
1733 * Prevent the remote side from maliciously writing to
1734 * files outside the target area by sending a filename
1735 * containing `../'. In fact, it shouldn't be sending
1736 * filenames with any slashes or colons in at all; so
1737 * we'll find the last slash, backslash or colon in the
1738 * filename and use only the part after that. (And
1741 * In addition, we also ensure here that if we're
1742 * copying a single file and the target is a directory
1743 * (common usage: `pscp host:filename .') the remote
1744 * can't send us a _different_ file name. We can
1745 * distinguish this case because `src' will be non-NULL
1746 * and the last component of that will fail to match
1747 * (the last component of) the name sent.
1749 * Well, not always; if `src' is a wildcard, we do
1750 * expect to get back filenames that don't correspond
1751 * exactly to it. Ideally in this case, we would like
1752 * to ensure that the returned filename actually
1753 * matches the wildcard pattern - but one of SCP's
1754 * protocol infelicities is that wildcard matching is
1755 * done at the server end _by the server's rules_ and
1756 * so in general this is infeasible. Hence, we only
1757 * accept filenames that don't correspond to `src' if
1758 * unsafe mode is enabled or we are using SFTP (which
1759 * resolves remote wildcards on the client side and can
1762 char *striptarget
, *stripsrc
;
1764 striptarget
= stripslashes(act
.name
, 1);
1765 if (striptarget
!= act
.name
) {
1766 tell_user(stderr
, "warning: remote host sent a compound"
1767 " pathname '%s'", act
.name
);
1768 tell_user(stderr
, " renaming local file to '%s'",
1773 * Also check to see if the target filename is '.' or
1774 * '..', or indeed '...' and so on because Windows
1775 * appears to interpret those like '..'.
1777 if (is_dots(striptarget
)) {
1778 bump("security violation: remote host attempted to write to"
1779 " a '.' or '..' path!");
1783 stripsrc
= stripslashes(src
, 1);
1784 if (strcmp(striptarget
, stripsrc
) &&
1785 !using_sftp
&& !scp_unsafe_mode
) {
1786 tell_user(stderr
, "warning: remote host tried to write "
1787 "to a file called '%s'", striptarget
);
1788 tell_user(stderr
, " when we requested a file "
1789 "called '%s'.", stripsrc
);
1790 tell_user(stderr
, " If this is a wildcard, "
1791 "consider upgrading to SSH 2 or using");
1792 tell_user(stderr
, " the '-unsafe' option. Renaming"
1793 " of this file has been disallowed.");
1794 /* Override the name the server provided with our own. */
1795 striptarget
= stripsrc
;
1799 if (targ
[0] != '\0')
1800 destfname
= dupcat(targ
, "\\", striptarget
, NULL
);
1802 destfname
= dupstr(striptarget
);
1805 * In this branch of the if, the target area is a
1806 * single file with an explicitly specified name in any
1807 * case, so there's no danger.
1809 destfname
= dupstr(targ
);
1811 attr
= GetFileAttributes(destfname
);
1812 exists
= (attr
!= (DWORD
) - 1);
1814 if (act
.action
== SCP_SINK_DIR
) {
1815 if (exists
&& (attr
& FILE_ATTRIBUTE_DIRECTORY
) == 0) {
1816 run_err("%s: Not a directory", destfname
);
1820 if (!CreateDirectory(destfname
, NULL
)) {
1821 run_err("%s: Cannot create directory", destfname
);
1825 sink(destfname
, NULL
);
1826 /* can we set the timestamp for directories ? */
1830 f
= CreateFile(destfname
, GENERIC_WRITE
, 0, NULL
,
1831 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, 0);
1832 if (f
== INVALID_HANDLE_VALUE
) {
1833 run_err("%s: Cannot create file", destfname
);
1837 if (scp_accept_filexfer())
1841 stat_starttime
= time(NULL
);
1843 stat_name
= stripslashes(destfname
, 1);
1846 while (received
< act
.size
) {
1847 char transbuf
[4096];
1848 DWORD blksize
, read
, written
;
1850 if (blksize
> act
.size
- received
)
1851 blksize
= act
.size
- received
;
1852 read
= scp_recv_filedata(transbuf
, blksize
);
1854 bump("Lost connection");
1857 if (!WriteFile(f
, transbuf
, read
, &written
, NULL
) ||
1860 /* FIXME: in sftp we can actually abort the transfer */
1862 printf("\r%-25.25s | %50s\n",
1864 "Write error.. waiting for end of file");
1869 if (time(NULL
) > stat_lasttime
||
1870 received
+ read
== act
.size
) {
1871 stat_lasttime
= time(NULL
);
1872 print_stats(stat_name
, act
.size
, stat_bytes
,
1873 stat_starttime
, stat_lasttime
);
1879 FILETIME actime
, wrtime
;
1880 TIME_POSIX_TO_WIN(act
.atime
, actime
);
1881 TIME_POSIX_TO_WIN(act
.mtime
, wrtime
);
1882 SetFileTime(f
, NULL
, &actime
, &wrtime
);
1887 run_err("%s: Write error", destfname
);
1890 (void) scp_finish_filerecv();
1897 * We will copy local files to a remote server.
1899 static void toremote(int argc
, char *argv
[])
1901 char *src
, *targ
, *host
, *user
;
1905 targ
= argv
[argc
- 1];
1907 /* Separate host from filename */
1911 bump("targ == NULL in toremote()");
1915 /* Substitute "." for emtpy target */
1917 /* Separate host and username */
1919 host
= strrchr(host
, '@');
1930 /* Find out if the source filespec covers multiple files
1931 if so, we should set the targetshouldbedirectory flag */
1933 WIN32_FIND_DATA fdat
;
1934 if (colon(argv
[0]) != NULL
)
1935 bump("%s: Remote to remote not supported", argv
[0]);
1936 fh
= FindFirstFile(argv
[0], &fdat
);
1937 if (fh
== INVALID_HANDLE_VALUE
)
1938 bump("%s: No such file or directory\n", argv
[0]);
1939 if (FindNextFile(fh
, &fdat
))
1940 targetshouldbedirectory
= 1;
1944 cmd
= smalloc(strlen(targ
) + 100);
1945 sprintf(cmd
, "scp%s%s%s%s -t %s",
1946 verbose ?
" -v" : "",
1947 recursive ?
" -r" : "",
1948 preserve ?
" -p" : "",
1949 targetshouldbedirectory ?
" -d" : "", targ
);
1950 do_cmd(host
, user
, cmd
);
1953 scp_source_setup(targ
, targetshouldbedirectory
);
1955 for (i
= 0; i
< argc
- 1; i
++) {
1956 char *srcpath
, *last
;
1958 WIN32_FIND_DATA fdat
;
1960 if (colon(src
) != NULL
) {
1961 tell_user(stderr
, "%s: Remote to remote not supported\n", src
);
1967 * Trim off the last pathname component of `src', to
1968 * provide the base pathname which will be prepended to
1969 * filenames returned from Find{First,Next}File.
1971 srcpath
= dupstr(src
);
1972 last
= stripslashes(srcpath
, 1);
1975 dir
= FindFirstFile(src
, &fdat
);
1976 if (dir
== INVALID_HANDLE_VALUE
) {
1977 run_err("%s: No such file or directory", src
);
1983 * Ensure that . and .. are never matched by wildcards,
1984 * but only by deliberate action.
1986 if (!strcmp(fdat
.cFileName
, ".") ||
1987 !strcmp(fdat
.cFileName
, "..")) {
1989 * Find*File has returned a special dir. We require
1990 * that _either_ `src' ends in a backslash followed
1991 * by that string, _or_ `src' is precisely that
1994 int len
= strlen(src
), dlen
= strlen(fdat
.cFileName
);
1995 if (len
== dlen
&& !strcmp(src
, fdat
.cFileName
)) {
1997 } else if (len
> dlen
+ 1 && src
[len
- dlen
- 1] == '\\' &&
1998 !strcmp(src
+ len
- dlen
, fdat
.cFileName
)) {
2001 continue; /* ignore this one */
2003 filename
= dupcat(srcpath
, fdat
.cFileName
, NULL
);
2006 } while (FindNextFile(dir
, &fdat
));
2013 * We will copy files from a remote server to the local machine.
2015 static void tolocal(int argc
, char *argv
[])
2017 char *src
, *targ
, *host
, *user
;
2021 bump("More than one remote source not supported");
2026 /* Separate host from filename */
2030 bump("Local to local copy not supported");
2034 /* Substitute "." for empty filename */
2036 /* Separate username and hostname */
2038 host
= strrchr(host
, '@');
2048 cmd
= smalloc(strlen(src
) + 100);
2049 sprintf(cmd
, "scp%s%s%s%s -f %s",
2050 verbose ?
" -v" : "",
2051 recursive ?
" -r" : "",
2052 preserve ?
" -p" : "",
2053 targetshouldbedirectory ?
" -d" : "", src
);
2054 do_cmd(host
, user
, cmd
);
2057 if (scp_sink_setup(src
, preserve
, recursive
))
2064 * We will issue a list command to get a remote directory.
2066 static void get_dir_list(int argc
, char *argv
[])
2068 char *src
, *host
, *user
;
2074 /* Separate host from filename */
2078 bump("Local to local copy not supported");
2082 /* Substitute "." for empty filename */
2084 /* Separate username and hostname */
2086 host
= strrchr(host
, '@');
2096 cmd
= smalloc(4 * strlen(src
) + 100);
2097 strcpy(cmd
, "ls -la '");
2098 p
= cmd
+ strlen(cmd
);
2099 for (q
= src
; *q
; q
++) {
2112 do_cmd(host
, user
, cmd
);
2116 scp_sftp_listdir(src
);
2118 while (ssh_scp_recv(&c
, 1) > 0)
2119 tell_char(stdout
, c
);
2124 * Initialize the Win$ock driver.
2126 static void init_winsock(void)
2131 winsock_ver
= MAKEWORD(1, 1);
2132 if (WSAStartup(winsock_ver
, &wsadata
))
2133 bump("Unable to initialise WinSock");
2134 if (LOBYTE(wsadata
.wVersion
) != 1 || HIBYTE(wsadata
.wVersion
) != 1)
2135 bump("WinSock version is incompatible with 1.1");
2139 * Short description of parameters.
2141 static void usage(void)
2143 printf("PuTTY Secure Copy client\n");
2144 printf("%s\n", ver
);
2145 printf("Usage: pscp [options] [user@]host:source target\n");
2147 (" pscp [options] source [source...] [user@]host:target\n");
2148 printf(" pscp [options] -ls user@host:filespec\n");
2149 printf("Options:\n");
2150 printf(" -p preserve file attributes\n");
2151 printf(" -q quiet, don't show statistics\n");
2152 printf(" -r copy directories recursively\n");
2153 printf(" -v show verbose messages\n");
2154 printf(" -P port connect to specified port\n");
2155 printf(" -pw passw login with specified password\n");
2156 printf(" -unsafe allow server-side wildcards (DANGEROUS)\n");
2159 * -gui is an internal option, used by GUI front ends to get
2160 * pscp to pass progress reports back to them. It's not an
2161 * ordinary user-accessible option, so it shouldn't be part of
2162 * the command-line help. The only people who need to know
2163 * about it are programmers, and they can read the source.
2166 (" -gui hWnd GUI mode with the windows handle for receiving messages\n");
2172 * Main program (no, really?)
2174 int main(int argc
, char *argv
[])
2178 default_protocol
= PROT_TELNET
;
2180 flags
= FLAG_STDERR
;
2181 ssh_get_line
= &get_line
;
2185 for (i
= 1; i
< argc
; i
++) {
2186 if (argv
[i
][0] != '-')
2188 if (strcmp(argv
[i
], "-v") == 0)
2189 verbose
= 1, flags
|= FLAG_VERBOSE
;
2190 else if (strcmp(argv
[i
], "-r") == 0)
2192 else if (strcmp(argv
[i
], "-p") == 0)
2194 else if (strcmp(argv
[i
], "-q") == 0)
2196 else if (strcmp(argv
[i
], "-h") == 0 || strcmp(argv
[i
], "-?") == 0)
2198 else if (strcmp(argv
[i
], "-P") == 0 && i
+ 1 < argc
)
2199 portnumber
= atoi(argv
[++i
]);
2200 else if (strcmp(argv
[i
], "-pw") == 0 && i
+ 1 < argc
)
2201 password
= argv
[++i
];
2202 else if (strcmp(argv
[i
], "-gui") == 0 && i
+ 1 < argc
) {
2203 gui_hwnd
= argv
[++i
];
2205 } else if (strcmp(argv
[i
], "-ls") == 0)
2207 else if (strcmp(argv
[i
], "-unsafe") == 0)
2208 scp_unsafe_mode
= 1;
2209 else if (strcmp(argv
[i
], "--") == 0) {
2222 get_dir_list(argc
, argv
);
2229 targetshouldbedirectory
= 1;
2231 if (colon(argv
[argc
- 1]) != NULL
)
2232 toremote(argc
, argv
);
2234 tolocal(argc
, argv
);
2237 if (back
!= NULL
&& back
->socket() != NULL
) {
2239 back
->special(TS_EOF
);
2240 ssh_scp_recv(&ch
, 1);
2245 /* GUI Adaptation - August 2000 */
2247 unsigned int msg_id
= WM_RET_ERR_CNT
;
2249 msg_id
= WM_LS_RET_ERR_CNT
;
2251 ((HWND
) atoi(gui_hwnd
), msg_id
, (WPARAM
) errs
,
2252 0 /*lParam */ ))SleepEx(1000, TRUE
);
2254 return (errs
== 0 ?
0 : 1);