X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/3bbbd50d44728c2bc72f5abee5d73020d592bb0e..6226c9390d23d6868edde63b9568891cd88631cc:/psftp.c diff --git a/psftp.c b/psftp.c index 71a8f274..d07ee8b0 100644 --- a/psftp.c +++ b/psftp.c @@ -189,6 +189,11 @@ static int bare_name_compare(const void *av, const void *bv) return strcmp(*a, *b); } +static void not_connected(void) +{ + printf("psftp: not connected to a host; use \"open host.name\"\n"); +} + /* ---------------------------------------------------------------------- * The meat of the `get' and `put' commands. */ @@ -199,7 +204,7 @@ 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; /* @@ -376,17 +381,17 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart) 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); } - if (!fp) { + if (!file) { printf("local: unable to open %s\n", outfname); sftp_register(req = fxp_close_send(fh)); @@ -398,11 +403,21 @@ 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) { + 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); } @@ -437,7 +452,7 @@ 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; @@ -456,7 +471,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()); @@ -473,7 +488,7 @@ 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; /* @@ -603,8 +618,8 @@ 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); + if (!file) { printf("local: unable to open %s\n", fname); return 0; } @@ -619,7 +634,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) fh = fxp_open_recv(pktin, rreq); if (!fh) { - printf("%s: %s\n", outfname, fxp_error()); + printf("%s: open for write: %s\n", outfname, fxp_error()); return 0; } @@ -644,12 +659,9 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart) 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); } @@ -668,7 +680,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; @@ -696,7 +708,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; } @@ -869,7 +881,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; @@ -886,7 +898,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); @@ -936,11 +948,11 @@ int sftp_cmd_quit(struct sftp_command *cmd) int sftp_cmd_close(struct sftp_command *cmd) { if (back == NULL) { - printf("psftp: not connected to a host; use \"open host.name\"\n"); + not_connected(); return 0; } - if (back != NULL && back->socket(backhandle) != NULL) { + if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); sftp_recvdata(&ch, 1); @@ -966,7 +978,7 @@ int sftp_cmd_ls(struct sftp_command *cmd) int i; if (back == NULL) { - printf("psftp: not connected to a host; use \"open host.name\"\n"); + not_connected(); return 0; } @@ -1002,7 +1014,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; } @@ -1088,7 +1100,7 @@ int sftp_cmd_cd(struct sftp_command *cmd) char *dir; if (back == NULL) { - printf("psftp: not connected to a host; use \"open host.name\"\n"); + not_connected(); return 0; } @@ -1098,7 +1110,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; } @@ -1131,7 +1143,7 @@ int sftp_cmd_cd(struct sftp_command *cmd) int sftp_cmd_pwd(struct sftp_command *cmd) { if (back == NULL) { - printf("psftp: not connected to a host; use \"open host.name\"\n"); + not_connected(); return 0; } @@ -1155,7 +1167,7 @@ int sftp_general_get(struct sftp_command *cmd, int restart, int multiple) int recurse = FALSE; if (back == NULL) { - printf("psftp: not connected to a host; use \"open host.name\"\n"); + not_connected(); return 0; } @@ -1209,7 +1221,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; } @@ -1269,7 +1281,7 @@ int sftp_general_put(struct sftp_command *cmd, int restart, int multiple) int recurse = FALSE; if (back == NULL) { - printf("psftp: not connected to a host; use \"open host.name\"\n"); + not_connected(); return 0; } @@ -1320,7 +1332,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); @@ -1370,7 +1382,7 @@ int sftp_cmd_mkdir(struct sftp_command *cmd) int i, ret; if (back == NULL) { - printf("psftp: not connected to a host; use \"open host.name\"\n"); + not_connected(); return 0; } @@ -1383,7 +1395,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; } @@ -1394,9 +1406,9 @@ int sftp_cmd_mkdir(struct sftp_command *cmd) if (!result) { printf("mkdir %s: %s\n", dir, fxp_error()); - sfree(dir); ret = 0; - } + } else + printf("mkdir %s: OK\n", dir); sfree(dir); } @@ -1420,6 +1432,8 @@ static int sftp_action_rmdir(void *vctx, char *dir) return 0; } + printf("rmdir %s: OK\n", dir); + return 1; } @@ -1428,7 +1442,7 @@ int sftp_cmd_rmdir(struct sftp_command *cmd) int i, ret; if (back == NULL) { - printf("psftp: not connected to a host; use \"open host.name\"\n"); + not_connected(); return 0; } @@ -1460,6 +1474,8 @@ static int sftp_action_rm(void *vctx, char *fname) return 0; } + printf("rm %s: OK\n", fname); + return 1; } @@ -1468,7 +1484,7 @@ int sftp_cmd_rm(struct sftp_command *cmd) int i, ret; if (back == NULL) { - printf("psftp: not connected to a host; use \"open host.name\"\n"); + not_connected(); return 0; } @@ -1527,7 +1543,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; } @@ -1563,7 +1579,7 @@ int sftp_cmd_mv(struct sftp_command *cmd) int i, ret; if (back == NULL) { - printf("psftp: not connected to a host; use \"open host.name\"\n"); + not_connected(); return 0; } @@ -1574,7 +1590,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; } @@ -1657,7 +1673,7 @@ int sftp_cmd_chmod(struct sftp_command *cmd) struct sftp_context_chmod actx, *ctx = &actx; if (back == NULL) { - printf("psftp: not connected to a host; use \"open host.name\"\n"); + not_connected(); return 0; } @@ -1891,7 +1907,7 @@ static struct sftp_cmd_lookup { }, { "cd", TRUE, "change your remote working directory", - " [ ]\n" + " [ ]\n" " Change the remote working directory for your SFTP session.\n" " If a new working directory is not supplied, you will be\n" " returned to your home directory.\n", @@ -1899,10 +1915,11 @@ static struct sftp_cmd_lookup { }, { "chmod", TRUE, "change file permissions and modes", - " ( | ) \n" - " Change the file permissions on a file or directory.\n" - " can be any octal Unix permission specifier.\n" - " Alternatively, can include:\n" + " [ ... ]\n" + " Change the file permissions on one or more remote files or\n" + " directories.\n" + " can be any octal Unix permission specifier.\n" + " Alternatively, can include the following modifiers:\n" " u+r make file readable by owning user\n" " u+w make file writable by owning user\n" " u+x make file executable by owning user\n" @@ -1933,16 +1950,16 @@ static struct sftp_cmd_lookup { sftp_cmd_close }, { - "del", TRUE, "delete a file", - " \n" - " Delete a file.\n", + "del", TRUE, "delete files on the remote server", + " [ ... ]\n" + " Delete a file or files from the server.\n", sftp_cmd_rm }, { "delete", FALSE, "del", NULL, sftp_cmd_rm }, { - "dir", TRUE, "list contents of a remote directory", + "dir", TRUE, "list remote files", " [ ]/[ ]\n" " List the contents of a specified directory on the server.\n" " If is not given, the current working directory\n" @@ -1999,9 +2016,9 @@ static struct sftp_cmd_lookup { sftp_cmd_mget }, { - "mkdir", TRUE, "create a directory on the remote server", - " \n" - " Creates a directory with the given name on the server.\n", + "mkdir", TRUE, "create directories on the remote server", + " [ ... ]\n" + " Creates directories with the given names on the server.\n", sftp_cmd_mkdir }, { @@ -2014,18 +2031,22 @@ static struct sftp_cmd_lookup { sftp_cmd_mput }, { - "mv", TRUE, "move or rename a file on the remote server", - " \n" - " Moves or renames the file on the server,\n" - " so that it is accessible under the name .\n", + "mv", TRUE, "move or rename file(s) on the remote server", + " [ ... ] \n" + " Moves or renames (s) on the server to ,\n" + " also on the server.\n" + " If specifies an existing directory, then \n" + " may be a wildcard, and multiple s may be given; all\n" + " source files are moved into .\n" + " Otherwise, must specify a single file, which is moved\n" + " or renamed so that it is accessible under the name .\n", sftp_cmd_mv }, { "open", TRUE, "connect to a host", " [@] []\n" " Establishes an SFTP connection to a given host. Only usable\n" - " when you did not already specify a host name on the command\n" - " line.\n", + " when you are not already connected to a server.\n", sftp_cmd_open }, { @@ -2048,7 +2069,7 @@ static struct sftp_cmd_lookup { sftp_cmd_quit }, { - "reget", TRUE, "continue downloading a file", + "reget", TRUE, "continue downloading files", " [ -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" @@ -2065,7 +2086,7 @@ static struct sftp_cmd_lookup { sftp_cmd_mv }, { - "reput", TRUE, "continue uploading a file", + "reput", TRUE, "continue uploading files", " [ -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" @@ -2078,10 +2099,11 @@ static struct sftp_cmd_lookup { sftp_cmd_rm }, { - "rmdir", TRUE, "remove a directory on the remote server", - " \n" + "rmdir", TRUE, "remove directories on the remote server", + " [ ... ]\n" " Removes the directory with the given name on the server.\n" - " The directory will not be removed unless it is empty.\n", + " The directory will not be removed unless it is empty.\n" + " Wildcards may be used to specify multiple directories.\n", sftp_cmd_rmdir } }; @@ -2508,6 +2530,15 @@ int from_backend(void *frontend, int is_stderr, const char *data, int datalen) return 0; } +int from_backend_untrusted(void *frontend_handle, const char *data, int len) +{ + /* + * No "untrusted" output should get here (the way the code is + * currently, it's all diverted by FLAG_STDERR). + */ + assert(!"Unexpected call to from_backend_untrusted()"); + return 0; /* not reached */ +} int sftp_recvdata(char *buf, int len) { outptr = (unsigned char *) buf; @@ -2536,7 +2567,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 */ } @@ -2557,6 +2588,8 @@ static void usage(void) printf("%s\n", ver); printf("Usage: psftp [options] [user@]host\n"); printf("Options:\n"); + printf(" -V print version information and exit\n"); + printf(" -pgpfp print PGP key fingerprints and exit\n"); printf(" -b file use specified batchfile\n"); printf(" -bc output batchfile commands\n"); printf(" -be don't stop batchfile processing if errors\n"); @@ -2569,8 +2602,9 @@ static void usage(void) 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(" -noagent disable use of Pageant\n"); + printf(" -agent enable use of Pageant\n"); printf(" -batch disable all interactive prompts\n"); - printf(" -V print version information\n"); cleanup_exit(1); } @@ -2697,17 +2731,6 @@ static int psftp_connect(char *userhost, char *user, int portnumber) strncpy(cfg.username, user, sizeof(cfg.username) - 1); cfg.username[sizeof(cfg.username) - 1] = '\0'; } - if (!cfg.username[0]) { - if (!console_get_line("login as: ", - cfg.username, sizeof(cfg.username), FALSE)) { - fprintf(stderr, "psftp: no username, aborting\n"); - cleanup_exit(1); - } else { - int len = strlen(cfg.username); - if (cfg.username[len - 1] == '\n') - cfg.username[len - 1] = '\0'; - } - } if (portnumber) cfg.port = portnumber; @@ -2727,7 +2750,7 @@ static int psftp_connect(char *userhost, char *user, int portnumber) cfg.nopty = TRUE; /* - * Set up fallback option, for SSH1 servers or servers with the + * Set up fallback option, for SSH-1 servers or servers with the * sftp subsystem not enabled but the server binary installed * in the usual place. We only support fallback on Unix * systems, and we use a kludgy piece of shellery which should @@ -2803,7 +2826,6 @@ int psftp_main(int argc, char *argv[]) #endif ; cmdline_tooltype = TOOLTYPE_FILETRANSFER; - ssh_get_line = &console_get_line; sk_init(); userhost = user = NULL; @@ -2834,6 +2856,9 @@ int psftp_main(int argc, char *argv[]) } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0) { usage(); + } else if (strcmp(argv[i], "-pgpfp") == 0) { + pgp_fingerprints(); + return 1; } else if (strcmp(argv[i], "-V") == 0) { version(); } else if (strcmp(argv[i], "-batch") == 0) { @@ -2884,7 +2909,7 @@ int psftp_main(int argc, char *argv[]) do_sftp(mode, modeflags, batchfile); - if (back != NULL && back->socket(backhandle) != NULL) { + if (back != NULL && back->connected(backhandle)) { char ch; back->special(backhandle, TS_EOF); sftp_recvdata(&ch, 1);