X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/6a8ec97c80056ad30fcb3ca61b4c9eee16ad0578..3ee4eedaec9cad4b5b2ff0f40567fa2e57a942a9:/psftp.c diff --git a/psftp.c b/psftp.c index 04a631c1..ab287dfd 100644 --- a/psftp.c +++ b/psftp.c @@ -16,6 +16,8 @@ #include "sftp.h" #include "int64.h" +const char *const appname = "PSFTP"; + /* * Since SFTP is a request-response oriented protocol, it requires * no buffer management: when we send data, we stop and wait for an @@ -34,7 +36,8 @@ void do_sftp_cleanup(); char *pwd, *homedir; static Backend *back; static void *backhandle; -static Config cfg; +static Conf *conf; +int sent_eof = FALSE; /* ---------------------------------------------------------------------- * Higher-level helper functions used in commands. @@ -128,8 +131,12 @@ char *canonify(char *name) assert(rreq == req); canonname = fxp_realpath_recv(pktin, rreq); - if (!canonname) - return fullname; /* even that failed; give up */ + if (!canonname) { + /* Even that failed. Restore our best guess at the + * constructed filename and give up */ + fullname[i] = '/'; /* restore slash and last component */ + return fullname; + } /* * We have a canonical name for all but the last path @@ -204,8 +211,9 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) struct sftp_request *req, *rreq; struct fxp_xfer *xfer; uint64 offset; - FILE *fp; + WFile *file; int ret, shown_err = FALSE; + struct fxp_attrs attrs; /* * In recursive mode, see if we're dealing with a directory. @@ -213,7 +221,6 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) * subsequent FXP_OPEN will return a usable error message.) */ if (recurse) { - struct fxp_attrs attrs; int result; sftp_register(req = fxp_stat_send(fname)); @@ -317,22 +324,24 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) * If none of them exists, of course, we start at 0. */ i = 0; - while (i < nnames) { - char *nextoutfname; - int ret; - if (outfname) - nextoutfname = dir_file_cat(outfname, - ournames[i]->filename); - else - nextoutfname = dupstr(ournames[i]->filename); - ret = (file_type(nextoutfname) == FILE_TYPE_NONEXISTENT); - sfree(nextoutfname); - if (ret) - break; - i++; - } - if (i > 0) - i--; + if (restart) { + while (i < nnames) { + char *nextoutfname; + int ret; + if (outfname) + nextoutfname = dir_file_cat(outfname, + ournames[i]->filename); + else + nextoutfname = dupstr(ournames[i]->filename); + ret = (file_type(nextoutfname) == FILE_TYPE_NONEXISTENT); + sfree(nextoutfname); + if (ret) + break; + i++; + } + if (i > 0) + i--; + } /* * Now we're ready to recurse. Starting at ournames[i] @@ -375,23 +384,29 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) } } - sftp_register(req = fxp_open_send(fname, SSH_FXF_READ)); + sftp_register(req = fxp_stat_send(fname)); + rreq = sftp_find_request(pktin = sftp_recv()); + assert(rreq == req); + if (!fxp_stat_recv(pktin, rreq, &attrs)) + attrs.flags = 0; + + sftp_register(req = fxp_open_send(fname, SSH_FXF_READ, NULL)); rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fh = fxp_open_recv(pktin, rreq); if (!fh) { - printf("%s: %s\n", fname, fxp_error()); + printf("%s: open for read: %s\n", fname, fxp_error()); return 0; } if (restart) { - fp = fopen(outfname, "rb+"); + file = open_existing_wfile(outfname, NULL); } else { - fp = fopen(outfname, "wb"); + file = open_new_file(outfname, GET_PERMISSIONS(attrs)); } - if (!fp) { + if (!file) { printf("local: unable to open %s\n", outfname); sftp_register(req = fxp_close_send(fh)); @@ -403,11 +418,22 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) } if (restart) { - long posn; - fseek(fp, 0L, SEEK_END); - posn = ftell(fp); - printf("reget: restarting at file position %ld\n", posn); - offset = uint64_make(0, posn); + char decbuf[30]; + if (seek_file(file, uint64_make(0,0) , FROM_END) == -1) { + close_wfile(file); + printf("reget: cannot restart %s - file too large\n", + outfname); + sftp_register(req = fxp_close_send(fh)); + rreq = sftp_find_request(pktin = sftp_recv()); + assert(rreq == req); + fxp_close_recv(pktin, rreq); + + return 0; + } + + offset = get_file_posn(file); + uint64_decimal(offset, decbuf); + printf("reget: restarting at file position %s\n", decbuf); } else { offset = uint64_make(0, 0); } @@ -442,11 +468,12 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) wpos = 0; while (wpos < len) { - wlen = fwrite(buf + wpos, 1, len - wpos, fp); + wlen = write_to_file(file, buf + wpos, len - wpos); if (wlen <= 0) { printf("error while writing local file\n"); ret = 0; xfer_set_error(xfer); + break; } wpos += wlen; } @@ -461,7 +488,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) xfer_cleanup(xfer); - fclose(fp); + close_wfile(file); sftp_register(req = fxp_close_send(fh)); rreq = sftp_find_request(pktin = sftp_recv()); @@ -478,8 +505,10 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) struct sftp_packet *pktin; struct sftp_request *req, *rreq; uint64 offset; - FILE *fp; + RFile *file; int ret, err, eof; + struct fxp_attrs attrs; + long permissions; /* * In recursive mode, see if we're dealing with a directory. @@ -487,7 +516,6 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) * subsequent fopen will return an error message.) */ if (recurse && file_type(fname) == FILE_TYPE_DIRECTORY) { - struct fxp_attrs attrs; int result; int nnames, namesize; char *name, **ournames; @@ -554,23 +582,25 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) * If none of them exists, of course, we start at 0. */ i = 0; - while (i < nnames) { - char *nextoutfname; - nextoutfname = dupcat(outfname, "/", ournames[i], NULL); - sftp_register(req = fxp_stat_send(nextoutfname)); - rreq = sftp_find_request(pktin = sftp_recv()); - assert(rreq == req); - result = fxp_stat_recv(pktin, rreq, &attrs); - sfree(nextoutfname); - if (!result) - break; - i++; - } - if (i > 0) - i--; + if (restart) { + while (i < nnames) { + char *nextoutfname; + nextoutfname = dupcat(outfname, "/", ournames[i], NULL); + sftp_register(req = fxp_stat_send(nextoutfname)); + rreq = sftp_find_request(pktin = sftp_recv()); + assert(rreq == req); + result = fxp_stat_recv(pktin, rreq, &attrs); + sfree(nextoutfname); + if (!result) + break; + i++; + } + if (i > 0) + i--; + } - /* - * Now we're ready to recurse. Starting at ournames[i] + /* + * Now we're ready to recurse. Starting at ournames[i] * and continuing on to the end of the list, we * construct a new source and target file name, and * call sftp_put_file again. @@ -608,23 +638,27 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) return 1; } - fp = fopen(fname, "rb"); - if (!fp) { + file = open_existing_file(fname, NULL, NULL, NULL, &permissions); + if (!file) { printf("local: unable to open %s\n", fname); return 0; } + attrs.flags = 0; + PUT_PERMISSIONS(attrs, permissions); if (restart) { - sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE)); + sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE, &attrs)); } else { sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE | - SSH_FXF_CREAT | SSH_FXF_TRUNC)); + SSH_FXF_CREAT | SSH_FXF_TRUNC, + &attrs)); } rreq = sftp_find_request(pktin = sftp_recv()); assert(rreq == req); fh = fxp_open_recv(pktin, rreq); if (!fh) { - printf("%s: %s\n", outfname, fxp_error()); + close_rfile(file); + printf("%s: open for write: %s\n", outfname, fxp_error()); return 0; } @@ -639,22 +673,21 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) ret = fxp_fstat_recv(pktin, rreq, &attrs); if (!ret) { + close_rfile(file); printf("read size of %s: %s\n", outfname, fxp_error()); return 0; } if (!(attrs.flags & SSH_FILEXFER_ATTR_SIZE)) { + close_rfile(file); printf("read size of %s: size was not given\n", outfname); return 0; } offset = attrs.size; uint64_decimal(offset, decbuf); printf("reput: restarting at file position %s\n", decbuf); - if (uint64_compare(offset, uint64_make(0, LONG_MAX)) > 0) { - printf("reput: remote file is larger than we can deal with\n"); - return 0; - } - if (fseek(fp, offset.lo, SEEK_SET) != 0) - fseek(fp, 0, SEEK_END); /* *shrug* */ + + if (seek_file((WFile *)file, offset, FROM_START) != 0) + seek_file((WFile *)file, uint64_make(0,0), FROM_END); /* *shrug* */ } else { offset = uint64_make(0, 0); } @@ -673,7 +706,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) int len, ret; while (xfer_upload_ready(xfer) && !err && !eof) { - len = fread(buffer, 1, sizeof(buffer), fp); + len = read_from_file(file, buffer, sizeof(buffer)); if (len == -1) { printf("error while reading local file\n"); err = 1; @@ -687,7 +720,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) if (!xfer_done(xfer)) { pktin = sftp_recv(); ret = xfer_upload_gotpkt(xfer, pktin); - if (!ret) { + if (ret <= 0 && !err) { printf("error while writing: %s\n", fxp_error()); err = 1; } @@ -701,7 +734,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) assert(rreq == req); fxp_close_recv(pktin, rreq); - fclose(fp); + close_rfile(file); return ret; } @@ -797,7 +830,17 @@ char *sftp_wildcard_get_filename(SftpWildcardMatcher *swcm) printf("%s: reading directory: %s\n", swcm->prefix, fxp_error()); return NULL; - } + } else if (swcm->names->nnames == 0) { + /* + * Another failure mode which we treat as EOF is if + * the server reports success from FXP_READDIR but + * returns no actual names. This is unusual, since + * from most servers you'd expect at least "." and + * "..", but there's nothing forbidding a server from + * omitting those if it wants to. + */ + return NULL; + } swcm->namepos = 0; } @@ -874,7 +917,7 @@ int wildcard_iterate(char *filename, int (*func)(void *, char *), void *ctx) while ( (newname = sftp_wildcard_get_filename(swcm)) != NULL ) { cname = canonify(newname); if (!cname) { - printf("%s: %s\n", newname, fxp_error()); + printf("%s: canonify: %s\n", newname, fxp_error()); ret = 0; } matched = TRUE; @@ -891,7 +934,7 @@ int wildcard_iterate(char *filename, int (*func)(void *, char *), void *ctx) } else { cname = canonify(unwcfname); if (!cname) { - printf("%s: %s\n", filename, fxp_error()); + printf("%s: canonify: %s\n", filename, fxp_error()); ret = 0; } ret = func(ctx, cname); @@ -945,9 +988,10 @@ int sftp_cmd_close(struct sftp_command *cmd) return 0; } - if (back != NULL && back->socket(backhandle) != NULL) { + if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); + sent_eof = TRUE; sftp_recvdata(&ch, 1); } do_sftp_cleanup(); @@ -1007,7 +1051,7 @@ int sftp_cmd_ls(struct sftp_command *cmd) cdir = canonify(dir); if (!cdir) { - printf("%s: %s\n", dir, fxp_error()); + printf("%s: canonify: %s\n", dir, fxp_error()); sfree(unwcdir); return 0; } @@ -1103,7 +1147,7 @@ int sftp_cmd_cd(struct sftp_command *cmd) dir = canonify(cmd->words[1]); if (!dir) { - printf("%s: %s\n", dir, fxp_error()); + printf("%s: canonify: %s\n", dir, fxp_error()); return 0; } @@ -1214,7 +1258,7 @@ int sftp_general_get(struct sftp_command *cmd, int restart, int multiple) fname = canonify(origwfname); if (!fname) { - printf("%s: %s\n", origwfname, fxp_error()); + printf("%s: canonify: %s\n", origwfname, fxp_error()); sfree(unwcfname); return 0; } @@ -1325,7 +1369,7 @@ int sftp_general_put(struct sftp_command *cmd, int restart, int multiple) outfname = canonify(origoutfname); if (!outfname) { - printf("%s: %s\n", origoutfname, fxp_error()); + printf("%s: canonify: %s\n", origoutfname, fxp_error()); if (wcm) { sfree(wfname); finish_wildcard_matching(wcm); @@ -1388,7 +1432,7 @@ int sftp_cmd_mkdir(struct sftp_command *cmd) for (i = 1; i < cmd->nwords; i++) { dir = canonify(cmd->words[i]); if (!dir) { - printf("%s: %s\n", dir, fxp_error()); + printf("%s: canonify: %s\n", dir, fxp_error()); return 0; } @@ -1536,7 +1580,7 @@ static int sftp_action_mv(void *vctx, char *srcfname) newname = dupcat(ctx->dstfname, "/", p, NULL); newcanon = canonify(newname); if (!newcanon) { - printf("%s: %s\n", newname, fxp_error()); + printf("%s: canonify: %s\n", newname, fxp_error()); sfree(newname); return 0; } @@ -1583,7 +1627,7 @@ int sftp_cmd_mv(struct sftp_command *cmd) ctx->dstfname = canonify(cmd->words[cmd->nwords-1]); if (!ctx->dstfname) { - printf("%s: %s\n", ctx->dstfname, fxp_error()); + printf("%s: canonify: %s\n", ctx->dstfname, fxp_error()); return 0; } @@ -2220,6 +2264,11 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags) cmd->words = sresize(cmd->words, cmd->wordssize, char *); cmd->words[0] = dupstr("!"); cmd->words[1] = dupstr(p+1); + } else if (*p == '#') { + /* + * Special case: comment. Entire line is ignored. + */ + cmd->nwords = cmd->wordssize = 0; } else { /* @@ -2238,10 +2287,13 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags) * >this has "quotes" in< * >and"this"< */ - while (*p) { + while (1) { /* skip whitespace */ while (*p && (*p == ' ' || *p == '\t')) p++; + /* terminate loop */ + if (!*p) + break; /* mark start of word */ q = r = p; /* q sits at start, r writes word */ quoting = 0; @@ -2325,6 +2377,7 @@ void do_sftp_cleanup() char ch; if (back) { back->special(backhandle, TS_EOF); + sent_eof = TRUE; sftp_recvdata(&ch, 1); back->free(backhandle); sftp_cleanup_request(); @@ -2491,7 +2544,8 @@ int from_backend(void *frontend, int is_stderr, const char *data, int datalen) */ if (is_stderr) { if (len > 0) - fwrite(data, 1, len, stderr); + if (fwrite(data, 1, len, stderr) < len) + /* oh well */; return 0; } @@ -2532,6 +2586,19 @@ int from_backend_untrusted(void *frontend_handle, const char *data, int len) assert(!"Unexpected call to from_backend_untrusted()"); return 0; /* not reached */ } +int from_backend_eof(void *frontend) +{ + /* + * We expect to be the party deciding when to close the + * connection, so if we see EOF before we sent it ourselves, we + * should panic. + */ + if (!sent_eof) { + connection_fatal(frontend, + "Received unexpected end-of-file from SFTP server"); + } + return FALSE; +} int sftp_recvdata(char *buf, int len) { outptr = (unsigned char *) buf; @@ -2560,7 +2627,7 @@ int sftp_recvdata(char *buf, int len) } while (outlen > 0) { - if (ssh_sftp_loop_iteration() < 0) + if (back->exitcode(backhandle) >= 0 || ssh_sftp_loop_iteration() < 0) return 0; /* doom */ } @@ -2636,32 +2703,30 @@ static int psftp_connect(char *userhost, char *user, int portnumber) */ if (!loaded_session) { /* Try to load settings for `host' into a temporary config */ - Config cfg2; - cfg2.host[0] = '\0'; - do_defaults(host, &cfg2); - if (cfg2.host[0] != '\0') { + Conf *conf2 = conf_new(); + conf_set_str(conf2, CONF_host, ""); + do_defaults(host, conf2); + if (conf_get_str(conf2, CONF_host)[0] != '\0') { /* Settings present and include hostname */ /* Re-load data into the real config. */ - do_defaults(host, &cfg); + do_defaults(host, conf); } else { /* Session doesn't exist or mention a hostname. */ /* Use `host' as a bare hostname. */ - strncpy(cfg.host, host, sizeof(cfg.host) - 1); - cfg.host[sizeof(cfg.host) - 1] = '\0'; + conf_set_str(conf, CONF_host, host); } } else { /* Patch in hostname `host' to session details. */ - strncpy(cfg.host, host, sizeof(cfg.host) - 1); - cfg.host[sizeof(cfg.host) - 1] = '\0'; + conf_set_str(conf, CONF_host, host); } /* * Force use of SSH. (If they got the protocol wrong we assume the * port is useless too.) */ - if (cfg.protocol != PROT_SSH) { - cfg.protocol = PROT_SSH; - cfg.port = 22; + if (conf_get_int(conf, CONF_protocol) != PROT_SSH) { + conf_set_int(conf, CONF_protocol, PROT_SSH); + conf_set_int(conf, CONF_port, 22); } /* @@ -2670,77 +2735,82 @@ static int psftp_connect(char *userhost, char *user, int portnumber) * work for SFTP. (Can be overridden with `-1' option.) * But if it says `2 only' or `2', respect which. */ - if (cfg.sshprot != 2 && cfg.sshprot != 3) - cfg.sshprot = 2; + if ((conf_get_int(conf, CONF_sshprot) & ~1) != 2) /* is it 2 or 3? */ + conf_set_int(conf, CONF_sshprot, 2); /* * Enact command-line overrides. */ - cmdline_run_saved(&cfg); + cmdline_run_saved(conf); /* - * Trim leading whitespace off the hostname if it's there. + * Muck about with the hostname in various ways. */ { - int space = strspn(cfg.host, " \t"); - memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space); - } - - /* See if host is of the form user@host */ - if (cfg.host[0] != '\0') { - char *atsign = strrchr(cfg.host, '@'); - /* Make sure we're not overflowing the user field */ - if (atsign) { - if (atsign - cfg.host < sizeof cfg.username) { - strncpy(cfg.username, cfg.host, atsign - cfg.host); - cfg.username[atsign - cfg.host] = '\0'; - } - memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1)); - } - } + char *hostbuf = dupstr(conf_get_str(conf, CONF_host)); + char *host = hostbuf; + char *p, *q; - /* - * Trim a colon suffix off the hostname if it's there. - */ - cfg.host[strcspn(cfg.host, ":")] = '\0'; + /* + * Trim leading whitespace. + */ + host += strspn(host, " \t"); - /* - * Remove any remaining whitespace from the hostname. - */ - { - int p1 = 0, p2 = 0; - while (cfg.host[p2] != '\0') { - if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') { - cfg.host[p1] = cfg.host[p2]; - p1++; + /* + * See if host is of the form user@host, and separate out + * the username if so. + */ + if (host[0] != '\0') { + char *atsign = strrchr(host, '@'); + if (atsign) { + *atsign = '\0'; + conf_set_str(conf, CONF_username, host); + host = atsign + 1; } - p2++; } - cfg.host[p1] = '\0'; + + /* + * Remove any remaining whitespace. + */ + p = hostbuf; + q = host; + while (*q) { + if (*q != ' ' && *q != '\t') + *p++ = *q; + q++; + } + *p = '\0'; + + conf_set_str(conf, CONF_host, hostbuf); + sfree(hostbuf); } /* Set username */ if (user != NULL && user[0] != '\0') { - strncpy(cfg.username, user, sizeof(cfg.username) - 1); - cfg.username[sizeof(cfg.username) - 1] = '\0'; + conf_set_str(conf, CONF_username, user); } if (portnumber) - cfg.port = portnumber; + conf_set_int(conf, CONF_port, portnumber); /* * Disable scary things which shouldn't be enabled for simple * things like SCP and SFTP: agent forwarding, port forwarding, * X forwarding. */ - cfg.x11_forward = 0; - cfg.agentfwd = 0; - cfg.portfwd[0] = cfg.portfwd[1] = '\0'; + conf_set_int(conf, CONF_x11_forward, 0); + conf_set_int(conf, CONF_agentfwd, 0); + conf_set_int(conf, CONF_ssh_simple, TRUE); + { + char *key; + while ((key = conf_get_str_nthstrkey(conf, CONF_portfwd, 0)) != NULL) + conf_del_str_str(conf, CONF_portfwd, key); + } /* Set up subsystem name. */ - strcpy(cfg.remote_cmd, "sftp"); - cfg.ssh_subsys = TRUE; - cfg.nopty = TRUE; + conf_set_str(conf, CONF_remote_cmd, "sftp"); + conf_set_int(conf, CONF_ssh_subsys, TRUE); + conf_set_int(conf, CONF_nopty, TRUE); /* * Set up fallback option, for SSH-1 servers or servers with the @@ -2759,24 +2829,31 @@ static int psftp_connect(char *userhost, char *user, int portnumber) * obvious pathnames and then give up, and when it does give up * it will print the preferred pathname in the error messages. */ - cfg.remote_cmd_ptr2 = - "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" - "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" - "exec sftp-server"; - cfg.ssh_subsys2 = FALSE; + conf_set_str(conf, CONF_remote_cmd2, + "test -x /usr/lib/sftp-server &&" + " exec /usr/lib/sftp-server\n" + "test -x /usr/local/lib/sftp-server &&" + " exec /usr/local/lib/sftp-server\n" + "exec sftp-server"); + conf_set_int(conf, CONF_ssh_subsys2, FALSE); back = &ssh_backend; - err = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, - 0, cfg.tcp_keepalives); + err = back->init(NULL, &backhandle, conf, + conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), + &realhost, 0, + conf_get_int(conf, CONF_tcp_keepalives)); if (err != NULL) { fprintf(stderr, "ssh_init: %s\n", err); return 1; } - logctx = log_init(NULL, &cfg); + logctx = log_init(NULL, conf); back->provide_logctx(backhandle, logctx); console_provide_logctx(logctx); while (!back->sendok(backhandle)) { + if (back->exitcode(backhandle) >= 0) + return 1; if (ssh_sftp_loop_iteration() < 0) { fprintf(stderr, "ssh_init: error during SSH connection setup\n"); return 1; @@ -2811,7 +2888,6 @@ int psftp_main(int argc, char *argv[]) int mode = 0; int modeflags = 0; char *batchfile = NULL; - int errors = 0; flags = FLAG_STDERR | FLAG_INTERACTIVE #ifdef FLAG_SYNCAGENT @@ -2824,10 +2900,10 @@ int psftp_main(int argc, char *argv[]) userhost = user = NULL; /* Load Default Settings before doing anything else. */ - do_defaults(NULL, &cfg); + conf = conf_new(); + do_defaults(NULL, conf); loaded_session = FALSE; - errors = 0; for (i = 1; i < argc; i++) { int ret; if (argv[i][0] != '-') { @@ -2837,7 +2913,7 @@ int psftp_main(int argc, char *argv[]) userhost = dupstr(argv[i]); continue; } - ret = cmdline_process_param(argv[i], i+1socket(backhandle) != NULL) { + if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); + sent_eof = TRUE; sftp_recvdata(&ch, 1); } do_sftp_cleanup();