X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=pscp.c;h=5d8256dfa27c0578d877e9bc3dc64de01e723960;hb=415224eab5791f504c08146db901fe87837a19f6;hp=50bea9300bcbffac40b5d10eb9ef094638c20a9c;hpb=c925526e3fbf580a4df3e796fc78e22bbe33651d;p=PuTTY.git diff --git a/pscp.c b/pscp.c index 50bea930..5d8256df 100644 --- a/pscp.c +++ b/pscp.c @@ -41,15 +41,16 @@ static int try_sftp = 1; static int main_cmd_is_sftp = 0; static int fallback_cmd_is_sftp = 0; static int using_sftp = 0; +static int uploading = 0; static Backend *back; static void *backhandle; static Conf *conf; int sent_eof = FALSE; -static void source(char *src); -static void rsource(char *src); -static void sink(char *targ, char *src); +static void source(const char *src); +static void rsource(const char *src); +static void sink(const char *targ, const char *src); const char *const appname = "PSCP"; @@ -59,23 +60,14 @@ const char *const appname = "PSCP"; */ #define MAX_SCP_BUFSIZE 16384 -void ldisc_send(void *handle, char *buf, int len, int interactive) -{ - /* - * This is only here because of the calls to ldisc_send(NULL, - * 0) in ssh.c. Nothing in PSCP actually needs to use the ldisc - * as an ldisc. So if we get called with any real data, I want - * to know about it. - */ - assert(len == 0); -} +void ldisc_echoedit_update(void *handle) { } -static void tell_char(FILE * stream, char c) +static void tell_char(FILE *stream, char c) { fputc(c, stream); } -static void tell_str(FILE * stream, char *str) +static void tell_str(FILE *stream, const char *str) { unsigned int i; @@ -83,7 +75,7 @@ static void tell_str(FILE * stream, char *str) tell_char(stream, str[i]); } -static void tell_user(FILE * stream, char *fmt, ...) +static void tell_user(FILE *stream, const char *fmt, ...) { char *str, *str2; va_list ap; @@ -99,7 +91,7 @@ static void tell_user(FILE * stream, char *fmt, ...) /* * Print an error message and perform a fatal exit. */ -void fatalbox(char *fmt, ...) +void fatalbox(const char *fmt, ...) { char *str, *str2; va_list ap; @@ -114,7 +106,7 @@ void fatalbox(char *fmt, ...) cleanup_exit(1); } -void modalfatalbox(char *fmt, ...) +void modalfatalbox(const char *fmt, ...) { char *str, *str2; va_list ap; @@ -129,7 +121,20 @@ void modalfatalbox(char *fmt, ...) cleanup_exit(1); } -void connection_fatal(void *frontend, char *fmt, ...) +void nonfatal(const char *fmt, ...) +{ + char *str, *str2; + va_list ap; + va_start(ap, fmt); + str = dupvprintf(fmt, ap); + str2 = dupcat("Error: ", str, "\n", NULL); + sfree(str); + va_end(ap); + tell_str(stderr, str2); + sfree(str2); + errs++; +} +void connection_fatal(void *frontend, const char *fmt, ...) { char *str, *str2; va_list ap; @@ -218,11 +223,12 @@ int from_backend_untrusted(void *frontend_handle, const char *data, int len) int from_backend_eof(void *frontend) { /* - * We expect to be the party deciding when to close the + * We usually expect to be the party deciding when to close the * connection, so if we see EOF before we sent it ourselves, we - * should panic. + * should panic. The exception is if we're using old-style scp and + * downloading rather than uploading. */ - if (!sent_eof) { + if ((using_sftp || uploading) && !sent_eof) { connection_fatal(frontend, "Received unexpected end-of-file from server"); } @@ -296,7 +302,7 @@ static void ssh_scp_init(void) /* * Print an error message and exit after closing the SSH link. */ -static void bump(char *fmt, ...) +static void bump(const char *fmt, ...) { char *str, *str2; va_list ap; @@ -355,15 +361,9 @@ static void do_cmd(char *host, char *user, char *cmd) bump("Empty host name"); /* - * Remove fiddly bits of address: remove a colon suffix, and - * the square brackets around an IPv6 literal address. + * Remove a colon suffix. */ - if (host[0] == '[') { - host++; - host[strcspn(host, "]")] = '\0'; - } else { - host[strcspn(host, ":")] = '\0'; - } + host[host_strcspn(host, ":")] = '\0'; /* * If we haven't loaded session details already (e.g., from -load), @@ -514,6 +514,9 @@ static void do_cmd(char *host, char *user, char *cmd) back = &ssh_backend; + logctx = log_init(NULL, conf); + console_provide_logctx(logctx); + err = back->init(NULL, &backhandle, conf, conf_get_str(conf, CONF_host), conf_get_int(conf, CONF_port), @@ -521,9 +524,7 @@ static void do_cmd(char *host, char *user, char *cmd) conf_get_int(conf, CONF_tcp_keepalives)); if (err != NULL) bump("ssh_init: %s", err); - logctx = log_init(NULL, conf); back->provide_logctx(backhandle, logctx); - console_provide_logctx(logctx); ssh_scp_init(); if (verbose && realhost != NULL && errs == 0) tell_user(stderr, "Connected to %s", realhost); @@ -533,7 +534,7 @@ static void do_cmd(char *host, char *user, char *cmd) /* * Update statistic information about current file. */ -static void print_stats(char *name, uint64 size, uint64 done, +static void print_stats(const char *name, uint64 size, uint64 done, time_t start, time_t now) { float ratebs; @@ -598,47 +599,13 @@ static char *colon(char *str) if (str[0] == '\0' || str[0] == ':' || (str[0] != '[' && str[1] == ':')) return (NULL); - while (*str != '\0' && *str != ':' && *str != '/' && *str != '\\') { - if (*str == '[') { - /* Skip over IPv6 literal addresses - * (eg: 'jeroen@[2001:db8::1]:myfile.txt') */ - char *ipv6_end = strchr(str, ']'); - if (ipv6_end) { - str = ipv6_end; - } - } - str++; - } + str += host_strcspn(str, ":/\\"); if (*str == ':') return (str); else return (NULL); } -/* - * Return a pointer to the portion of str that comes after the last - * slash (or backslash or colon, if `local' is TRUE). - */ -static char *stripslashes(char *str, int local) -{ - char *p; - - if (local) { - p = strchr(str, ':'); - if (p) str = p+1; - } - - p = strrchr(str, '/'); - if (p) str = p+1; - - if (local) { - p = strrchr(str, '\\'); - if (p) str = p+1; - } - - return str; -} - /* * Determine whether a string is entirely composed of dots. */ @@ -692,6 +659,10 @@ int sftp_senddata(char *buf, int len) back->send(backhandle, buf, len); return 1; } +int sftp_sendbuffer(void) +{ + return back->sendbuffer(backhandle); +} /* ---------------------------------------------------------------------- * sftp-based replacement for the hacky `pscp -ls'. @@ -702,7 +673,7 @@ static int sftp_ls_compare(const void *av, const void *bv) const struct fxp_name *b = (const struct fxp_name *) bv; return strcmp(a->filename, b->filename); } -void scp_sftp_listdir(char *dirname) +void scp_sftp_listdir(const char *dirname) { struct fxp_handle *dirh; struct fxp_names *names; @@ -773,6 +744,8 @@ void scp_sftp_listdir(char *dirname) */ for (i = 0; i < nnames; i++) printf("%s\n", ournames[i].longname); + + sfree(ournames); } } @@ -799,7 +772,7 @@ static struct fxp_handle *scp_sftp_filehandle; static struct fxp_xfer *scp_sftp_xfer; static uint64 scp_sftp_fileoffset; -int scp_source_setup(char *target, int shouldbedir) +int scp_source_setup(const char *target, int shouldbedir) { if (using_sftp) { /* @@ -865,7 +838,7 @@ int scp_send_filetimes(unsigned long mtime, unsigned long atime) } } -int scp_send_filename(char *name, uint64 size, int permissions) +int scp_send_filename(const char *name, uint64 size, int permissions) { if (using_sftp) { char *fullname; @@ -891,6 +864,7 @@ int scp_send_filename(char *name, uint64 size, int permissions) if (!scp_sftp_filehandle) { tell_user(stderr, "pscp: unable to open %s: %s", fullname, fxp_error()); + sfree(fullname); errs++; return 1; } @@ -1019,7 +993,7 @@ void scp_restore_remotepath(char *data) scp_sftp_remotepath = data; } -int scp_send_dirname(char *name, int modes) +int scp_send_dirname(const char *name, int modes) { if (using_sftp) { char *fullname; @@ -1059,6 +1033,7 @@ int scp_send_dirname(char *name, int modes) !(attrs.permissions & 0040000)) { tell_user(stderr, "unable to create directory %s: %s", fullname, err); + sfree(fullname); errs++; return 1; } @@ -1093,7 +1068,7 @@ int scp_send_enddir(void) * right at the start, whereas scp_sink_init is called to * initialise every level of recursion in the protocol. */ -int scp_sink_setup(char *source, int preserve, int recursive) +int scp_sink_setup(const char *source, int preserve, int recursive) { if (using_sftp) { char *newsource; @@ -1114,6 +1089,9 @@ int scp_sink_setup(char *source, int preserve, int recursive) if (!wc_unescape(newsource, source)) { /* Yes, here we go; it's a wildcard. Bah. */ char *dupsource, *lastpart, *dirpart, *wildcard; + + sfree(newsource); + dupsource = dupstr(source); lastpart = stripslashes(dupsource, 0); wildcard = dupstr(lastpart); @@ -1279,6 +1257,7 @@ int scp_get_sink_action(struct scp_sink_action *act) if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS)) { tell_user(stderr, "unable to identify %s: %s", fname, ret ? "file type not supplied" : fxp_error()); + if (must_free_fname) sfree(fname); errs++; return 1; } @@ -1521,7 +1500,7 @@ int scp_get_sink_action(struct scp_sink_action *act) { char sizestr[40]; - if (sscanf(act->buf, "%lo %s %n", &act->permissions, + if (sscanf(act->buf, "%lo %39s %n", &act->permissions, sizestr, &i) != 2) bump("Protocol error: Illegal file descriptor format"); act->size = uint64_from_decimal(sizestr); @@ -1659,12 +1638,12 @@ static void run_err(const char *fmt, ...) /* * Execute the source part of the SCP protocol. */ -static void source(char *src) +static void source(const char *src) { uint64 size; unsigned long mtime, atime; long permissions; - char *last; + const char *last; RFile *f; int attr; uint64 i; @@ -1684,7 +1663,7 @@ static void source(char *src) /* * Avoid . and .. directories. */ - char *p; + const char *p; p = strrchr(src, '/'); if (!p) p = strrchr(src, '\\'); @@ -1717,8 +1696,10 @@ static void source(char *src) return; } if (preserve) { - if (scp_send_filetimes(mtime, atime)) + if (scp_send_filetimes(mtime, atime)) { + close_rfile(f); return; + } } if (verbose) { @@ -1726,18 +1707,21 @@ static void source(char *src) uint64_decimal(size, sizestr); tell_user(stderr, "Sending file %s, size=%s", last, sizestr); } - if (scp_send_filename(last, size, permissions)) + if (scp_send_filename(last, size, permissions)) { + close_rfile(f); return; + } stat_bytes = uint64_make(0,0); stat_starttime = time(NULL); stat_lasttime = 0; +#define PSCP_SEND_BLOCK 4096 for (i = uint64_make(0,0); uint64_compare(i,size) < 0; - i = uint64_add32(i,4096)) { - char transbuf[4096]; - int j, k = 4096; + i = uint64_add32(i,PSCP_SEND_BLOCK)) { + char transbuf[PSCP_SEND_BLOCK]; + int j, k = PSCP_SEND_BLOCK; if (uint64_compare(uint64_add32(i, k),size) > 0) /* i + k > size */ k = (uint64_subtract(size, i)).lo; /* k = size - i; */ @@ -1768,9 +1752,9 @@ static void source(char *src) /* * Recursively send the contents of a directory. */ -static void rsource(char *src) +static void rsource(const char *src) { - char *last; + const char *last; char *save_target; DirHandle *dir; @@ -1812,7 +1796,7 @@ static void rsource(char *src) /* * Execute the sink part of the SCP protocol. */ -static void sink(char *targ, char *src) +static void sink(const char *targ, const char *src) { char *destfname; int targisdir = 0; @@ -1930,27 +1914,34 @@ static void sink(char *targ, char *src) if (act.action == SCP_SINK_DIR) { if (exists && attr != FILE_TYPE_DIRECTORY) { run_err("%s: Not a directory", destfname); + sfree(destfname); continue; } if (!exists) { if (!create_directory(destfname)) { run_err("%s: Cannot create directory", destfname); + sfree(destfname); continue; } } sink(destfname, NULL); /* can we set the timestamp for directories ? */ + sfree(destfname); continue; } f = open_new_file(destfname, act.permissions); if (f == NULL) { run_err("%s: Cannot create file", destfname); + sfree(destfname); continue; } - if (scp_accept_filexfer()) + if (scp_accept_filexfer()) { + sfree(destfname); + close_wfile(f); return; + } stat_bytes = uint64_make(0, 0); stat_starttime = time(NULL); @@ -1997,6 +1988,7 @@ static void sink(char *targ, char *src) close_wfile(f); if (wrerror) { run_err("%s: Write error", destfname); + sfree(destfname); continue; } (void) scp_finish_filerecv(); @@ -2010,21 +2002,26 @@ static void sink(char *targ, char *src) */ static void toremote(int argc, char *argv[]) { - char *src, *targ, *host, *user; + char *src, *wtarg, *host, *user; + const char *targ; char *cmd; int i, wc_type; - targ = argv[argc - 1]; + uploading = 1; + + wtarg = argv[argc - 1]; /* Separate host from filename */ - host = targ; - targ = colon(targ); - if (targ == NULL) - bump("targ == NULL in toremote()"); - *targ++ = '\0'; - if (*targ == '\0') - targ = "."; + host = wtarg; + wtarg = colon(wtarg); + if (wtarg == NULL) + bump("wtarg == NULL in toremote()"); + *wtarg++ = '\0'; /* Substitute "." for empty target */ + if (*wtarg == '\0') + targ = "."; + else + targ = wtarg; /* Separate host and username */ user = host; @@ -2100,24 +2097,29 @@ static void toremote(int argc, char *argv[]) */ static void tolocal(int argc, char *argv[]) { - char *src, *targ, *host, *user; + char *wsrc, *host, *user; + const char *src, *targ; char *cmd; + uploading = 0; + if (argc != 2) bump("More than one remote source not supported"); - src = argv[0]; + wsrc = argv[0]; targ = argv[1]; /* Separate host from filename */ - host = src; - src = colon(src); - if (src == NULL) + host = wsrc; + wsrc = colon(wsrc); + if (wsrc == NULL) bump("Local to local copy not supported"); - *src++ = '\0'; - if (*src == '\0') - src = "."; + *wsrc++ = '\0'; /* Substitute "." for empty filename */ + if (*wsrc == '\0') + src = "."; + else + src = wsrc; /* Separate username and hostname */ user = host; @@ -2150,21 +2152,25 @@ static void tolocal(int argc, char *argv[]) */ static void get_dir_list(int argc, char *argv[]) { - char *src, *host, *user; - char *cmd, *p, *q; + char *wsrc, *host, *user; + const char *src; + char *cmd, *p; + const char *q; char c; - src = argv[0]; + wsrc = argv[0]; /* Separate host from filename */ - host = src; - src = colon(src); - if (src == NULL) + host = wsrc; + wsrc = colon(wsrc); + if (wsrc == NULL) bump("Local file listing not supported"); - *src++ = '\0'; - if (*src == '\0') - src = "."; + *wsrc++ = '\0'; /* Substitute "." for empty filename */ + if (*wsrc == '\0') + src = "."; + else + src = wsrc; /* Separate username and hostname */ user = host; @@ -2230,13 +2236,18 @@ static void usage(void) printf(" -1 -2 force use of particular SSH protocol version\n"); printf(" -4 -6 force use of IPv4 or IPv6\n"); printf(" -C enable compression\n"); - printf(" -i key private key file for authentication\n"); + printf(" -i key private key file for user authentication\n"); printf(" -noagent disable use of Pageant\n"); printf(" -agent enable use of Pageant\n"); + printf(" -hostkey aa:bb:cc:...\n"); + printf(" manually specify a host key (may be repeated)\n"); printf(" -batch disable all interactive prompts\n"); printf(" -unsafe allow server-side wildcards (DANGEROUS)\n"); printf(" -sftp force use of SFTP protocol\n"); printf(" -scp force use of SCP protocol\n"); + printf(" -sshlog file\n"); + printf(" -sshrawlog file\n"); + printf(" log protocol details to a file\n"); #if 0 /* * -gui is an internal option, used by GUI front ends to get @@ -2253,11 +2264,13 @@ static void usage(void) void version(void) { - printf("pscp: %s\n", ver); + char *buildinfo_text = buildinfo("\n"); + printf("pscp: %s\n%s\n", ver, buildinfo_text); + sfree(buildinfo_text); cleanup_exit(1); } -void cmdline_error(char *p, ...) +void cmdline_error(const char *p, ...) { va_list ap; fprintf(stderr, "pscp: "); @@ -2268,6 +2281,9 @@ void cmdline_error(char *p, ...) exit(1); } +const int share_can_be_downstream = TRUE; +const int share_can_be_upstream = FALSE; + /* * Main program. (Called `psftp_main' because it gets called from * *sftp.c; bit silly, I know, but it had to be called _something_.) @@ -2341,6 +2357,8 @@ int psftp_main(int argc, char *argv[]) argv += i; back = NULL; + platform_psftp_post_option_setup(); + if (list) { if (argc != 1) usage();