📄 psftp.c
字号:
} } fclose(fp); }}/* ---------------------------------------------------------------------- * Dirty bits: integration with PuTTY. */static int verbose = 0;/* * Print an error message and perform a fatal exit. */void fatalbox(char *fmt, ...){ char *str, *str2; va_list ap; va_start(ap, fmt); str = dupvprintf(fmt, ap); str2 = dupcat("Fatal: ", str, "\n", NULL); sfree(str); va_end(ap); fputs(str2, stderr); sfree(str2); cleanup_exit(1);}void modalfatalbox(char *fmt, ...){ char *str, *str2; va_list ap; va_start(ap, fmt); str = dupvprintf(fmt, ap); str2 = dupcat("Fatal: ", str, "\n", NULL); sfree(str); va_end(ap); fputs(str2, stderr); sfree(str2); cleanup_exit(1);}void connection_fatal(void *frontend, char *fmt, ...){ char *str, *str2; va_list ap; va_start(ap, fmt); str = dupvprintf(fmt, ap); str2 = dupcat("Fatal: ", str, "\n", NULL); sfree(str); va_end(ap); fputs(str2, stderr); sfree(str2); cleanup_exit(1);}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 PSFTP 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);}/* * In psftp, all agent requests should be synchronous, so this is a * never-called stub. */void agent_schedule_callback(void (*callback)(void *, void *, int), void *callback_ctx, void *data, int len){ assert(!"We shouldn't be here");}/* * Receive a block of data from the SSH link. Block until all data * is available. * * To do this, we repeatedly call the SSH protocol module, with our * own trap in from_backend() to catch the data that comes back. We * do this until we have enough data. */static unsigned char *outptr; /* where to put the data */static unsigned outlen; /* how much data required */static unsigned char *pending = NULL; /* any spare data */static unsigned pendlen = 0, pendsize = 0; /* length and phys. size of buffer */int from_backend(void *frontend, int is_stderr, const char *data, int datalen){ unsigned char *p = (unsigned char *) data; unsigned len = (unsigned) datalen; /* * stderr data is just spouted to local stderr and otherwise * ignored. */ if (is_stderr) { if (len > 0) fwrite(data, 1, len, stderr); return 0; } /* * If this is before the real session begins, just return. */ if (!outptr) return 0; if ((outlen > 0) && (len > 0)) { unsigned used = outlen; if (used > len) used = len; memcpy(outptr, p, used); outptr += used; outlen -= used; p += used; len -= used; } if (len > 0) { if (pendsize < pendlen + len) { pendsize = pendlen + len + 4096; pending = sresize(pending, pendsize, unsigned char); } memcpy(pending + pendlen, p, len); pendlen += len; } return 0;}int sftp_recvdata(char *buf, int len){ outptr = (unsigned char *) buf; outlen = len; /* * See if the pending-input block contains some of what we * need. */ if (pendlen > 0) { unsigned pendused = pendlen; if (pendused > outlen) pendused = outlen; memcpy(outptr, pending, pendused); memmove(pending, pending + pendused, pendlen - pendused); outptr += pendused; outlen -= pendused; pendlen -= pendused; if (pendlen == 0) { pendsize = 0; sfree(pending); pending = NULL; } if (outlen == 0) return 1; } while (outlen > 0) { if (ssh_sftp_loop_iteration() < 0) return 0; /* doom */ } return 1;}int sftp_senddata(char *buf, int len){ back->send(backhandle, buf, len); return 1;}/* * Short description of parameters. */static void usage(void){ printf("PuTTY Secure File Transfer (SFTP) client\n"); printf("%s\n", ver); printf("Usage: psftp [options] [user@]host\n"); printf("Options:\n"); printf(" -b file use specified batchfile\n"); printf(" -bc output batchfile commands\n"); printf(" -be don't stop batchfile processing if errors\n"); printf(" -v show verbose messages\n"); printf(" -load sessname Load settings from saved session\n"); printf(" -l user connect with specified username\n"); printf(" -P port connect to specified port\n"); printf(" -pw passw login with specified password\n"); printf(" -1 -2 force use of particular SSH protocol version\n"); printf(" -C enable compression\n"); printf(" -i key private key file for authentication\n"); printf(" -batch disable all interactive prompts\n"); printf(" -V print version information\n"); cleanup_exit(1);}static void version(void){ printf("psftp: %s\n", ver); cleanup_exit(1);}/* * Connect to a host. */static int psftp_connect(char *userhost, char *user, int portnumber){ char *host, *realhost; const char *err; void *logctx; /* Separate host and username */ host = userhost; host = strrchr(host, '@'); if (host == NULL) { host = userhost; } else { *host++ = '\0'; if (user) { printf("psftp: multiple usernames specified; using \"%s\"\n", user); } else user = userhost; } /* * If we haven't loaded session details already (e.g., from -load), * try looking for a session called "host". */ 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') { /* Settings present and include hostname */ /* Re-load data into the real config. */ do_defaults(host, &cfg); } 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'; } } else { /* Patch in hostname `host' to session details. */ strncpy(cfg.host, host, sizeof(cfg.host) - 1); cfg.host[sizeof(cfg.host) - 1] = '\0'; } /* * 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 saved session / Default Settings says SSH-1 (`1 only' or `1'), * then change it to SSH-2, on the grounds that that's more likely to * 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; /* * Enact command-line overrides. */ cmdline_run_saved(&cfg); /* * Trim leading whitespace off the hostname if it's there. */ { 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)); } } /* * Trim a colon suffix off the hostname if it's there. */ cfg.host[strcspn(cfg.host, ":")] = '\0'; /* * 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++; } p2++; } cfg.host[p1] = '\0'; } /* Set username */ if (user != NULL && user[0] != '\0') { strncpy(cfg.username, user, sizeof(cfg.username) - 1); cfg.username[sizeof(cfg.username) - 1] = '\0'; } if (!cfg.username[0]) { printf("login as: "); fflush(stdout); if (!fgets(cfg.username, sizeof(cfg.username), stdin)) { fprintf(stderr, "psftp: 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; /* * 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'; /* Set up subsystem name. */ strcpy(cfg.remote_cmd, "sftp"); cfg.ssh_subsys = TRUE; cfg.nopty = TRUE; /* * Set up fallback option, for SSH1 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 * try to find sftp-server in various places (the obvious * systemwide spots /usr/lib and /usr/local/lib, and then the * user's PATH) and finally give up. * * test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server * test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server * exec sftp-server * * the idea being that this will attempt to use either of the * 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; back = &ssh_backend; err = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, 0, cfg.tcp_keepalives); if (err != NULL) { fprintf(stderr, "ssh_init: %s\n", err); return 1; } logctx = log_init(NULL, &cfg); back->provide_logctx(backhandle, logctx); console_provide_logctx(logctx); while (!back->sendok(backhandle)) { if (ssh_sftp_loop_iteration() < 0) { fprintf(stderr, "ssh_init: error during SSH connection setup\n"); return 1; } } if (verbose && realhost != NULL) printf("Connected to %s\n", realhost); if (realhost != NULL) sfree(realhost); return 0;}void cmdline_error(char *p, ...){ va_list ap; fprintf(stderr, "psftp: "); va_start(ap, p); vfprintf(stderr, p, ap); va_end(ap); fprintf(stderr, "\n try typing \"psftp -h\" for help\n"); exit(1);}/* * Main program. Parse arguments etc. */int psftp_main(int argc, char *argv[]){ int i; int portnumber = 0; char *userhost, *user; int mode = 0; int modeflags = 0; char *batchfile = NULL; int errors = 0; statics()->flags = FLAG_STDERR | FLAG_INTERACTIVE#ifdef FLAG_SYNCAGENT | FLAG_SYNCAGENT#endif ; cmdline_tooltype = TOOLTYPE_FILETRANSFER; statics()->ssh_get_line = &console_get_line; sk_init(); userhost = user = NULL; /* Load Default Settings before doing anything else. */ do_defaults(NULL, &cfg); loaded_session = FALSE; errors = 0; for (i = 1; i < argc; i++) { int ret; if (argv[i][0] != '-') { if (userhost) usage(); else userhost = dupstr(argv[i]); continue; } ret = cmdline_process_param(argv[i], i+1<argc?argv[i+1]:NULL, 1, &cfg); if (ret == -2) { cmdline_error("option \"%s\" requires an argument", argv[i]); } else if (ret == 2) { i++; /* skip next argument */ } else if (ret == 1) { /* We have our own verbosity in addition to `flags'. */ if (statics()->flags & FLAG_VERBOSE) verbose = 1; } else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "-?") == 0) { usage(); } else if (strcmp(argv[i], "-V") == 0) { version(); } else if (strcmp(argv[i], "-batch") == 0) { console_batch_mode = 1; } else if (strcmp(argv[i], "-b") == 0 && i + 1 < argc) { mode = 1; batchfile = argv[++i]; } else if (strcmp(argv[i], "-bc") == 0) { modeflags = modeflags | 1; } else if (strcmp(argv[i], "-be") == 0) { modeflags = modeflags | 2; } else if (strcmp(argv[i], "--") == 0) { i++; break; } else { cmdline_error("unknown option \"%s\"", argv[i]); } } argc -= i; argv += i; back = NULL; /* * If the loaded session provides a hostname, and a hostname has not * otherwise been specified, pop it in `userhost' so that * `psftp -load sessname' is sufficient to start a session. */ if (!userhost && cfg.host[0] != '\0') { userhost = dupstr(cfg.host); } /* * If a user@host string has already been provided, connect to * it now. */ if (userhost) { int ret; ret = psftp_connect(userhost, user, portnumber); sfree(userhost); if (ret) return 1; if (do_sftp_init()) return 1; } else { printf("psftp: no hostname specified; use \"open host.name\"" " to connect\n"); } do_sftp(mode, modeflags, batchfile); if (back != NULL && back->socket(backhandle) != NULL) { char ch; back->special(backhandle, TS_EOF); sftp_recvdata(&ch, 1); } random_save_seed(); cmdline_cleanup(); console_provide_logctx(NULL); do_sftp_cleanup(); backhandle = NULL; back = NULL; sk_cleanup(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -