X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/3394416cef1cce33c820cc00cbec2fc050bf189b..479fe1ba750b1cda0ad3a159f2727619555436b0:/psftp.c diff --git a/psftp.c b/psftp.c index de1964e8..0eedf9d2 100644 --- a/psftp.c +++ b/psftp.c @@ -41,14 +41,6 @@ static Config cfg; */ /* - * Determine whether a string is entirely composed of dots. - */ -static int is_dots(char *str) -{ - return str[strspn(str, ".")] == '\0'; -} - -/* * Attempt to canonify a pathname starting from the pwd. If * canonification fails, at least fall back to returning a _valid_ * pathname (though it may be ugly, eg /home/simon/../foobar). @@ -209,7 +201,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart, struct fxp_xfer *xfer; uint64 offset; FILE *fp; - int ret; + int ret, shown_err = FALSE; /* * In recursive mode, see if we're dealing with a directory. @@ -291,10 +283,19 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart, ournames = sresize(ournames, namesize, struct fxp_name *); } for (i = 0; i < names->nnames; i++) - if (!is_dots(names->names[i].filename) && + if (strcmp(names->names[i].filename, ".") && + strcmp(names->names[i].filename, "..") && (!wildcard || wc_match(wildcard, - names->names[i].filename))) - ournames[nnames++] = fxp_dup_name(&names->names[i]); + names->names[i].filename))) { + if (!vet_filename(names->names[i].filename)) { + printf("ignoring potentially dangerous server-" + "supplied filename '%s'\n", + names->names[i].filename); + } else { + ournames[nnames++] = + fxp_dup_name(&names->names[i]); + } + } fxp_free_names(names); } sftp_register(req = fxp_close_send(dirhandle)); @@ -442,7 +443,10 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart, ret = xfer_download_gotpkt(xfer, pktin); if (ret < 0) { - printf("error while reading: %s\n", fxp_error()); + if (!shown_err) { + printf("error while reading: %s\n", fxp_error()); + shown_err = TRUE; + } ret = 0; } @@ -767,6 +771,23 @@ int sftp_cmd_quit(struct sftp_command *cmd) return -1; } +int sftp_cmd_close(struct sftp_command *cmd) +{ + if (back == NULL) { + printf("psftp: not connected to a host; use \"open host.name\"\n"); + return 0; + } + + if (back != NULL && back->socket(backhandle) != NULL) { + char ch; + back->special(backhandle, TS_EOF); + sftp_recvdata(&ch, 1); + } + do_sftp_cleanup(); + + return 0; +} + /* * List a directory. If no arguments are given, list pwd; otherwise * list the directory given in words[1]. @@ -985,14 +1006,14 @@ int sftp_general_get(struct sftp_command *cmd, int restart, int multiple) } else if (!strcmp(cmd->words[i], "-r")) { recurse = TRUE; } else { - printf("get: unrecognised option '%s'\n", cmd->words[i]); + printf("%s: unrecognised option '%s'\n", cmd->words[0], cmd->words[i]); return 0; } i++; } if (i >= cmd->nwords) { - printf("get: expects a filename\n"); + printf("%s: expects a filename\n", cmd->words[0]); return 0; } @@ -1071,14 +1092,14 @@ int sftp_general_put(struct sftp_command *cmd, int restart, int multiple) } else if (!strcmp(cmd->words[i], "-r")) { recurse = TRUE; } else { - printf("put: unrecognised option '%s'\n", cmd->words[i]); + printf("%s: unrecognised option '%s'\n", cmd->words[0], cmd->words[i]); return 0; } i++; } if (i >= cmd->nwords) { - printf("put: expects a filename\n"); + printf("%s: expects a filename\n", cmd->words[0]); return 0; } @@ -1632,6 +1653,14 @@ static struct sftp_cmd_lookup { sftp_cmd_chmod }, { + "close", TRUE, "finish your SFTP session but do not quit PSFTP", + "\n" + " Terminates your SFTP session, but does not quit the PSFTP\n" + " program. You can then use \"open\" to start another SFTP\n" + " session, to the same server or to a different one.\n", + sftp_cmd_close + }, + { "del", TRUE, "delete a file", " \n" " Delete a file.\n", @@ -1642,10 +1671,12 @@ static struct sftp_cmd_lookup { }, { "dir", TRUE, "list contents of a remote directory", - " [ ]\n" + " [ ]/[ ]\n" " List the contents of a specified directory on the server.\n" " If is not given, the current working directory\n" - " will be listed.\n", + " is assumed.\n" + " If is given, it is treated as a set of files to\n" + " list; otherwise, all files are listed.\n", sftp_cmd_ls }, { @@ -1653,10 +1684,11 @@ static struct sftp_cmd_lookup { }, { "get", TRUE, "download a file from the server to your local machine", - " [ ]\n" + " [ -r ] [ -- ] [ ]\n" " Downloads a file on the server and stores it locally under\n" " the same name, or under a different one if you supply the\n" - " argument .\n", + " argument .\n" + " If -r specified, recursively fetch a directory.\n", sftp_cmd_get }, { @@ -1687,10 +1719,11 @@ static struct sftp_cmd_lookup { }, { "mget", TRUE, "download multiple files at once", - " [ ... ]\n" + " [ -r ] [ -- ] [ ... ]\n" " Downloads many files from the server, storing each one under\n" " the same name it has on the server side. You can use wildcards\n" - " such as \"*.c\" to specify lots of files at once.\n", + " such as \"*.c\" to specify lots of files at once.\n" + " If -r specified, recursively fetch files and directories.\n", sftp_cmd_mget }, { @@ -1704,7 +1737,8 @@ static struct sftp_cmd_lookup { " [ ... ]\n" " Uploads many files to the server, storing each one under the\n" " same name it has on the client side. You can use wildcards\n" - " such as \"*.c\" to specify lots of files at once.\n", + " such as \"*.c\" to specify lots of files at once.\n" + " If -r specified, recursively store files and directories.\n", sftp_cmd_mput }, { @@ -1724,10 +1758,11 @@ static struct sftp_cmd_lookup { }, { "put", TRUE, "upload a file from your local machine to the server", - " [ ]\n" + " [ -r ] [ -- ] [ ]\n" " Uploads a file to the server and stores it there under\n" " the same name, or under a different one if you supply the\n" - " argument .\n", + " argument .\n" + " If -r specified, recursively store a directory.\n", sftp_cmd_put }, { @@ -1742,10 +1777,11 @@ static struct sftp_cmd_lookup { }, { "reget", TRUE, "continue downloading a file", - " [ ]\n" + " [ -r ] [ -- ] [ ]\n" " Works exactly like the \"get\" command, but the local file\n" " must already exist. The download will begin at the end of the\n" - " file. This is for resuming a download that was interrupted.\n", + " file. This is for resuming a download that was interrupted.\n" + " If -r specified, resume interrupted \"get -r\".\n", sftp_cmd_reget }, { @@ -1758,10 +1794,11 @@ static struct sftp_cmd_lookup { }, { "reput", TRUE, "continue uploading a file", - " [ ]\n" + " [ -r ] [ -- ] [ ]\n" " Works exactly like the \"put\" command, but the remote file\n" " must already exist. The upload will begin at the end of the\n" - " file. This is for resuming an upload that was interrupted.\n", + " file. This is for resuming an upload that was interrupted.\n" + " If -r specified, resume interrupted \"put -r\".\n", sftp_cmd_reput }, { @@ -1866,7 +1903,7 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags) printf("psftp> "); line = fgetline(fp); } else { - line = ssh_sftp_get_cmdline("psftp> "); + line = ssh_sftp_get_cmdline("psftp> ", back == NULL); } if (!line || !*line) { @@ -2004,6 +2041,8 @@ void do_sftp_cleanup() sftp_recvdata(&ch, 1); back->free(backhandle); sftp_cleanup_request(); + back = NULL; + backhandle = NULL; } if (pwd) { sfree(pwd); @@ -2577,12 +2616,10 @@ int psftp_main(int argc, char *argv[]) back->special(backhandle, TS_EOF); sftp_recvdata(&ch, 1); } + do_sftp_cleanup(); random_save_seed(); cmdline_cleanup(); console_provide_logctx(NULL); - do_sftp_cleanup(); - backhandle = NULL; - back = NULL; sk_cleanup(); return 0;