X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/4a693cfc5c3ee0e639bbee0215345e921715ab04..3ee4eedaec9cad4b5b2ff0f40567fa2e57a942a9:/psftp.c diff --git a/psftp.c b/psftp.c index a42b162a..ab287dfd 100644 --- a/psftp.c +++ b/psftp.c @@ -37,6 +37,7 @@ char *pwd, *homedir; static Backend *back; static void *backhandle; static Conf *conf; +int sent_eof = FALSE; /* ---------------------------------------------------------------------- * Higher-level helper functions used in commands. @@ -212,6 +213,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) uint64 offset; WFile *file; int ret, shown_err = FALSE; + struct fxp_attrs attrs; /* * In recursive mode, see if we're dealing with a directory. @@ -219,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)); @@ -383,7 +384,13 @@ 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); @@ -396,7 +403,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) if (restart) { file = open_existing_wfile(outfname, NULL); } else { - file = open_new_file(outfname); + file = open_new_file(outfname, GET_PERMISSIONS(attrs)); } if (!file) { @@ -500,6 +507,8 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) uint64 offset; RFile *file; int ret, err, eof; + struct fxp_attrs attrs; + long permissions; /* * In recursive mode, see if we're dealing with a directory. @@ -507,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; @@ -630,16 +638,19 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) return 1; } - file = open_existing_file(fname, NULL, NULL, NULL); + 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); @@ -819,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; } @@ -970,6 +991,7 @@ int sftp_cmd_close(struct sftp_command *cmd) if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); + sent_eof = TRUE; sftp_recvdata(&ch, 1); } do_sftp_cleanup(); @@ -2265,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; @@ -2352,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(); @@ -2560,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; @@ -2884,12 +2923,14 @@ int psftp_main(int argc, char *argv[]) if (flags & FLAG_VERBOSE) verbose = 1; } else if (strcmp(argv[i], "-h") == 0 || - strcmp(argv[i], "-?") == 0) { + strcmp(argv[i], "-?") == 0 || + strcmp(argv[i], "--help") == 0) { usage(); } else if (strcmp(argv[i], "-pgpfp") == 0) { pgp_fingerprints(); return 1; - } else if (strcmp(argv[i], "-V") == 0) { + } else if (strcmp(argv[i], "-V") == 0 || + strcmp(argv[i], "--version") == 0) { version(); } else if (strcmp(argv[i], "-batch") == 0) { console_batch_mode = 1; @@ -2942,6 +2983,7 @@ int psftp_main(int argc, char *argv[]) if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); + sent_eof = TRUE; sftp_recvdata(&ch, 1); } do_sftp_cleanup();