X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/32874aeac8dacbca26663777b39a79efc5d8dc4b..5471d09ad63fc6216fb9c2a3b52ca9c93821a054:/scp.c diff --git a/scp.c b/scp.c index f414eb8f..b00500cf 100644 --- a/scp.c +++ b/scp.c @@ -46,12 +46,14 @@ #define WM_RET_ERR_CNT ( WM_APP_BASE+406 ) #define WM_LS_RET_ERR_CNT ( WM_APP_BASE+407 ) +static int list = 0; static int verbose = 0; static int recursive = 0; static int preserve = 0; static int targetshouldbedirectory = 0; static int statistics = 1; static int portnumber = 0; +static int prev_stats_len = 0; static char *password = NULL; static int errs = 0; /* GUI Adaptation - Sept 2000 */ @@ -70,11 +72,15 @@ static void sink(char *targ, char *src); static void tell_char(FILE * stream, char c); static void tell_str(FILE * stream, char *str); static void tell_user(FILE * stream, char *fmt, ...); -static void send_char_msg(unsigned int msg_id, char c); -static void send_str_msg(unsigned int msg_id, char *str); static void gui_update_stats(char *name, unsigned long size, int percentage, unsigned long elapsed); +/* + * The maximum amount of queued data we accept before we stop and + * wait for the server to process some. + */ +#define MAX_SCP_BUFSIZE 16384 + void logevent(char *string) { } @@ -94,6 +100,8 @@ void verify_ssh_host_key(char *host, int port, char *keytype, char *keystr, char *fingerprint) { int ret; + HANDLE hin; + DWORD savemode, i; static const char absentmsg[] = "The server's host key is not cached in the registry. You\n" @@ -103,8 +111,11 @@ void verify_ssh_host_key(char *host, int port, char *keytype, "%s\n" "If you trust this host, enter \"y\" to add the key to\n" "PuTTY's cache and carry on connecting.\n" - "If you do not trust this host, enter \"n\" to abandon the\n" - "connection.\n" "Continue connecting? (y/n) "; + "If you want to carry on connecting just once, without\n" + "adding the key to the cache, enter \"n\".\n" + "If you do not trust this host, press Return to abandon the\n" + "connection.\n" + "Store key in cache? (y/n) "; static const char wrongmsg[] = "WARNING - POTENTIAL SECURITY BREACH!\n" @@ -116,9 +127,9 @@ void verify_ssh_host_key(char *host, int port, char *keytype, "The new key fingerprint is:\n" "%s\n" "If you were expecting this change and trust the new key,\n" - "enter Yes to update PuTTY's cache and continue connecting.\n" + "enter \"y\" to update PuTTY's cache and continue connecting.\n" "If you want to carry on connecting but without updating\n" - "the cache, enter No.\n" + "the cache, enter \"n\".\n" "If you want to abandon the connection completely, press\n" "Return to cancel. Pressing Return is the ONLY guaranteed\n" "safe choice.\n" @@ -135,28 +146,29 @@ void verify_ssh_host_key(char *host, int port, char *keytype, if (ret == 0) /* success - key matched OK */ return; + if (ret == 2) { /* key was different */ fprintf(stderr, wrongmsg, fingerprint); fflush(stderr); - if (fgets(line, sizeof(line), stdin) && - line[0] != '\0' && line[0] != '\n') { - if (line[0] == 'y' || line[0] == 'Y') - store_host_key(host, port, keytype, keystr); - } else { - fprintf(stderr, abandoned); - fflush(stderr); - exit(0); - } } if (ret == 1) { /* key was absent */ fprintf(stderr, absentmsg, fingerprint); - if (fgets(line, sizeof(line), stdin) && - (line[0] == 'y' || line[0] == 'Y')) + fflush(stderr); + } + + hin = GetStdHandle(STD_INPUT_HANDLE); + GetConsoleMode(hin, &savemode); + SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT | + ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)); + ReadFile(hin, line, sizeof(line) - 1, &i, NULL); + SetConsoleMode(hin, savemode); + + if (line[0] != '\0' && line[0] != '\r' && line[0] != '\n') { + if (line[0] == 'y' || line[0] == 'Y') store_host_key(host, port, keytype, keystr); - else { - fprintf(stderr, abandoned); - exit(0); - } + } else { + fprintf(stderr, abandoned); + exit(0); } } @@ -239,6 +251,16 @@ void fatalbox(char *fmt, ...) va_end(ap); strcat(str, "\n"); tell_str(stderr, str); + errs++; + + if (gui_mode) { + unsigned int msg_id = WM_RET_ERR_CNT; + if (list) + msg_id = WM_LS_RET_ERR_CNT; + while (!PostMessage + ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs, + 0 /*lParam */ ))SleepEx(1000, TRUE); + } exit(1); } @@ -252,6 +274,16 @@ void connection_fatal(char *fmt, ...) va_end(ap); strcat(str, "\n"); tell_str(stderr, str); + errs++; + + if (gui_mode) { + unsigned int msg_id = WM_RET_ERR_CNT; + if (list) + msg_id = WM_LS_RET_ERR_CNT; + while (!PostMessage + ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs, + 0 /*lParam */ ))SleepEx(1000, TRUE); + } exit(1); } @@ -283,7 +315,7 @@ static unsigned char *outptr; /* where to put the data */ static unsigned outlen; /* how much data required */ static unsigned char *pending = NULL; /* any spare data */ static unsigned pendlen = 0, pendsize = 0; /* length and phys. size of buffer */ -void from_backend(int is_stderr, char *data, int datalen) +int from_backend(int is_stderr, char *data, int datalen) { unsigned char *p = (unsigned char *) data; unsigned len = (unsigned) datalen; @@ -294,7 +326,7 @@ void from_backend(int is_stderr, char *data, int datalen) */ if (is_stderr) { fwrite(data, 1, len, stderr); - return; + return 0; } inbuf_head = 0; @@ -303,7 +335,7 @@ void from_backend(int is_stderr, char *data, int datalen) * If this is before the real session begins, just return. */ if (!outptr) - return; + return 0; if (outlen > 0) { unsigned used = outlen; @@ -327,6 +359,19 @@ void from_backend(int is_stderr, char *data, int datalen) memcpy(pending + pendlen, p, len); pendlen += len; } + + return 0; +} +static int scp_process_network_event(void) +{ + fd_set readfds; + + FD_ZERO(&readfds); + FD_SET(scp_ssh_socket, &readfds); + if (select(1, &readfds, NULL, NULL, NULL) < 0) + return 0; /* doom */ + select_result((WPARAM) scp_ssh_socket, (LPARAM) FD_READ); + return 1; } static int ssh_scp_recv(unsigned char *buf, int len) { @@ -356,13 +401,8 @@ static int ssh_scp_recv(unsigned char *buf, int len) } while (outlen > 0) { - fd_set readfds; - - FD_ZERO(&readfds); - FD_SET(scp_ssh_socket, &readfds); - if (select(1, &readfds, NULL, NULL, NULL) < 0) + if (!scp_process_network_event()) return 0; /* doom */ - select_result((WPARAM) scp_ssh_socket, (LPARAM) FD_READ); } return len; @@ -398,12 +438,23 @@ static void bump(char *fmt, ...) va_end(ap); strcat(str, "\n"); tell_str(stderr, str); + errs++; if (back != NULL && back->socket() != NULL) { char ch; back->special(TS_EOF); ssh_scp_recv(&ch, 1); } + + if (gui_mode) { + unsigned int msg_id = WM_RET_ERR_CNT; + if (list) + msg_id = WM_LS_RET_ERR_CNT; + while (!PostMessage + ((HWND) atoi(gui_hwnd), msg_id, (WPARAM) errs, + 0 /*lParam */ ))SleepEx(1000, TRUE); + } + exit(1); } @@ -517,6 +568,7 @@ static void do_cmd(char *host, char *user, char *cmd) ssh_scp_init(); if (verbose && realhost != NULL) tell_user(stderr, "Connected to %s\n", realhost); + sfree(realhost); } /* @@ -529,6 +581,7 @@ static void print_stats(char *name, unsigned long size, unsigned long done, unsigned long eta; char etastr[10]; int pct; + int len; /* GUI Adaptation - Sept 2000 */ if (gui_mode) @@ -549,8 +602,11 @@ static void print_stats(char *name, unsigned long size, unsigned long done, pct = (int) (100.0 * (float) done / size); - printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%", - name, done / 1024, ratebs / 1024.0, etastr, pct); + len = printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%", + name, done / 1024, ratebs / 1024.0, etastr, pct); + if (len < prev_stats_len) + printf("%*s", prev_stats_len - len, ""); + prev_stats_len = len; if (done == size) printf("\n"); @@ -710,15 +766,15 @@ static void source(char *src) if (response()) return; - if (statistics) { - stat_bytes = 0; - stat_starttime = time(NULL); - stat_lasttime = 0; - } + stat_bytes = 0; + stat_starttime = time(NULL); + stat_lasttime = 0; for (i = 0; i < size; i += 4096) { char transbuf[4096]; DWORD j, k = 4096; + int bufsize; + if (i + k > size) k = size - i; if (!ReadFile(f, transbuf, k, &j, NULL) || j != k) { @@ -726,7 +782,7 @@ static void source(char *src) printf("\n"); bump("%s: Read error", src); } - back->send(transbuf, k); + bufsize = back->send(transbuf, k); if (statistics) { stat_bytes += k; if (time(NULL) != stat_lasttime || i + k == size) { @@ -735,6 +791,18 @@ static void source(char *src) stat_starttime, stat_lasttime); } } + + /* + * If the network transfer is backing up - that is, the + * remote site is not accepting data as fast as we can + * produce it - then we must loop on network events until + * we have space in the buffer again. + */ + while (bufsize > MAX_SCP_BUFSIZE) { + if (!scp_process_network_event()) + bump("%s: Network error occurred", src); + bufsize = back->sendbuffer(); + } } CloseHandle(f); @@ -905,17 +973,15 @@ static void sink(char *targ, char *src) back->send("", 1); - if (statistics) { - stat_bytes = 0; - stat_starttime = time(NULL); - stat_lasttime = 0; - if ((stat_name = strrchr(namebuf, '/')) == NULL) - stat_name = namebuf; - else - stat_name++; - if (strrchr(stat_name, '\\') != NULL) - stat_name = strrchr(stat_name, '\\') + 1; - } + stat_bytes = 0; + stat_starttime = time(NULL); + stat_lasttime = 0; + if ((stat_name = strrchr(namebuf, '/')) == NULL) + stat_name = namebuf; + else + stat_name++; + if (strrchr(stat_name, '\\') != NULL) + stat_name = strrchr(stat_name, '\\') + 1; for (i = 0; i < size; i += 4096) { char transbuf[4096]; @@ -1235,7 +1301,6 @@ static void usage(void) int main(int argc, char *argv[]) { int i; - int list = 0; default_protocol = PROT_TELNET;