📄 psftp.c
字号:
{
struct sftp_packet *pktin;
struct sftp_request *req, *rreq;
/*
* Do protocol initialisation.
*/
if (!fxp_init()) {
FzSFtpIpc_Error1("Fatal: unable to initialise SFTP: %s", fxp_error());
return 1; /* failure */
}
/*
* Find out where our home directory is.
*/
sftp_register(req = fxp_realpath_send("."));
rreq = sftp_find_request(pktin = sftp_recv());
assert(rreq == req);
homedir = fxp_realpath_recv(pktin, rreq);
if (!homedir) {
FzSFtpIpc_Status1("Warning: failed to resolve home directory: %s",
fxp_error());
homedir = dupstr(".");
} else {
FzSFtpIpc_Status1("Remote working directory is %s", homedir);
}
pwd = dupstr(homedir);
FzSFtpIpc_SendRequest(SFTP_DATAID_CTS_CONNECTED, 0, 0);
return 0;
}
/* ----------------------------------------------------------------------
* 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, NULL);
sfree(str);
va_end(ap);
FzSFtpIpc_FatalError(str2);
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, NULL);
sfree(str);
va_end(ap);
FzSFtpIpc_FatalError(str2);
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, NULL);
sfree(str);
va_end(ap);
FzSFtpIpc_FatalError(str2);
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;
}
/*
* Connect to a host.
*/
static int psftp_connect(char *userhost, char *user, int portnumber, int use_compression, int protocol)
{
char *host, *realhost;
const char *err;
/* 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;
}
/* Try to load settings for this host */
do_defaults(host, &cfg);
if (cfg.host[0] == '\0') {
/* No settings for this host; use defaults */
do_defaults(NULL, &cfg);
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;
}
/*
* 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 = strchr(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;
/* SFTP uses SSH2 by default always */
cfg.sshprot = 2;
/* Override compression and protocol */
if (use_compression == 1)
cfg.compression = 1;
else if (use_compression == 2)
cfg.compression = 0;
if (protocol == 1)
cmdline_process_param("-1", 0, 0, &cfg);
else if (protocol == 2)
cmdline_process_param("-2", 0, 0, &cfg);
/*
* 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;
}
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);
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);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
bLTrace=TRUE;
flags = FLAG_STDERR | FLAG_INTERACTIVE | FLAG_VERBOSE | FLAG_SYNCAGENT;
cmdline_tooltype = TOOLTYPE_FILETRANSFER;
ssh_get_line = &console_get_line;
sk_init();
if (!FzSFtpIpc_Init(lpCmdLine))
{
MessageBoxA(0, "Error: You can't start FzSFtp directly. It can only by started from FileZilla when connecting to an SFTP server.", "FzSFtp Error", MB_OK);
return 1;
}
FzSFtpIpc_Trace("FzSFtp started and initialized.");
while (TRUE)
{
char pMem[20480];
DWORD nID, nDataLength;
BOOL res=FzSFtpIpc_ReceiveRequest(&nID, &nDataLength, pMem);
if (!res)
break;
switch(nID)
{
case SFTP_DATAID_STC_CONNECT:
if (!nDataLength)
cleanup_exit(1);
{
char *host;
int port;
char *user;
char *pass;
int use_compression;
int protocol;
host = pMem;
port = *(int *)(pMem+strlen(host)+1);
user = pMem+strlen(host)+1+4;
pass = pMem+strlen(host)+1+4 + strlen(user) + 1;
use_compression = *(pMem+strlen(host)+1+4 + strlen(user) + 1 + strlen(pass) + 1);
protocol = *(pMem+strlen(host)+1+4 + strlen(user) + 1 + strlen(pass) + 2);
cmdline_process_param("-pw", pass, 0, &cfg);
if (psftp_connect (host, user, port, use_compression, protocol)<0)
cleanup_exit(1);
if (do_sftp_init())
cleanup_exit(1);
}
break;
case SFTP_DATAID_STC_PWD:
if (sftp_cmd_pwd(0)<0)
cleanup_exit(1);
break;
case SFTP_DATAID_STC_LIST:
if (sftp_cmd_ls()<0)
cleanup_exit(1);
break;
case SFTP_DATAID_STC_CD:
if (!nDataLength)
cleanup_exit(1);
if (sftp_cmd_cd(pMem)<0)
cleanup_exit(1);
break;
case SFTP_DATAID_STC_TRACE:
if (nDataLength!=4)
cleanup_exit(1);
bLTrace=*(BOOL*)pMem;
break;
case SFTP_DATAID_STC_MKD:
if (!nDataLength)
cleanup_exit(1);
sftp_cmd_mkdir(pMem);
break;
case SFTP_DATAID_STC_GET:
if (!nDataLength)
cleanup_exit(1);
sftp_general_get(pMem, pMem+strlen(pMem)+1, *(int *)(pMem+strlen(pMem)+1+strlen(pMem+strlen(pMem)+1)+1) );
break;
case SFTP_DATAID_STC_PUT:
if (!nDataLength)
cleanup_exit(1);
sftp_general_put(pMem, pMem+strlen(pMem)+1, *(int *)(pMem+strlen(pMem)+1+strlen(pMem+strlen(pMem)+1)+1) );
break;
case SFTP_DATAID_STC_RMD:
if (!nDataLength)
cleanup_exit(1);
if (sftp_cmd_rmdir(pMem)<0)
cleanup_exit(1);
break;
case SFTP_DATAID_STC_DELE:
if (!nDataLength)
cleanup_exit(1);
if (sftp_cmd_rm(pMem)<0)
cleanup_exit(1);
break;
case SFTP_DATAID_STC_RENAME:
if (!nDataLength)
cleanup_exit(1);
sftp_cmd_mv(pMem, pMem+strlen(pMem)+1);
break;
case SFTP_DATAID_STC_CHMOD:
if (!nDataLength)
cleanup_exit(1);
sftp_cmd_chmod(pMem, pMem+strlen(pMem)+1);
break;
case SFTP_DATAID_STC_FDREAD:
case SFTP_DATAID_STC_FDWRITE:
break;
default:
FzSFtpIpc_Trace("Unknown command, will be ignored");
break;
}
}
random_save_seed();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -