⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 psftp.c

📁 大名鼎鼎的远程登录软件putty的Symbian版源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * psftp.c: (platform-independent) front end for PSFTP. */#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <assert.h>#include <limits.h>#define PUTTY_DO_GLOBALS#include "putty.h"#include "psftp.h"#include "storage.h"#include "ssh.h"#include "sftp.h"#include "int64.h"/* * Since SFTP is a request-response oriented protocol, it requires * no buffer management: when we send data, we stop and wait for an * acknowledgement _anyway_, and so we can't possibly overfill our * send buffer. */static int psftp_connect(char *userhost, char *user, int portnumber);static int do_sftp_init(void);void do_sftp_cleanup();/* ---------------------------------------------------------------------- * sftp client state. */char *pwd, *homedir;static const Backend *back;static void *backhandle;static Config cfg;/* ---------------------------------------------------------------------- * Higher-level helper functions used in commands. *//* * 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). */char *canonify(char *name){    char *fullname, *canonname;    struct sftp_packet *pktin;    struct sftp_request *req, *rreq;    if (name[0] == '/') {	fullname = dupstr(name);    } else {	char *slash;	if (pwd[strlen(pwd) - 1] == '/')	    slash = "";	else	    slash = "/";	fullname = dupcat(pwd, slash, name, NULL);    }    sftp_register(req = fxp_realpath_send(fullname));    rreq = sftp_find_request(pktin = sftp_recv());    assert(rreq == req);    canonname = fxp_realpath_recv(pktin, rreq);    if (canonname) {	sfree(fullname);	return canonname;    } else {	/*	 * Attempt number 2. Some FXP_REALPATH implementations	 * (glibc-based ones, in particular) require the _whole_	 * path to point to something that exists, whereas others	 * (BSD-based) only require all but the last component to	 * exist. So if the first call failed, we should strip off	 * everything from the last slash onwards and try again,	 * then put the final component back on.	 * 	 * Special cases:	 * 	 *  - if the last component is "/." or "/..", then we don't	 *    bother trying this because there's no way it can work.	 * 	 *  - if the thing actually ends with a "/", we remove it	 *    before we start. Except if the string is "/" itself	 *    (although I can't see why we'd have got here if so,	 *    because surely "/" would have worked the first	 *    time?), in which case we don't bother.	 * 	 *  - if there's no slash in the string at all, give up in	 *    confusion (we expect at least one because of the way	 *    we constructed the string).	 */	int i;	char *returnname;	i = strlen(fullname);	if (i > 2 && fullname[i - 1] == '/')	    fullname[--i] = '\0';      /* strip trailing / unless at pos 0 */	while (i > 0 && fullname[--i] != '/');	/*	 * Give up on special cases.	 */	if (fullname[i] != '/' ||      /* no slash at all */	    !strcmp(fullname + i, "/.") ||	/* ends in /. */	    !strcmp(fullname + i, "/..") ||	/* ends in /.. */	    !strcmp(fullname, "/")) {	    return fullname;	}	/*	 * Now i points at the slash. Deal with the final special	 * case i==0 (ie the whole path was "/nonexistentfile").	 */	fullname[i] = '\0';	       /* separate the string */	if (i == 0) {	    sftp_register(req = fxp_realpath_send("/"));	} else {	    sftp_register(req = fxp_realpath_send(fullname));	}	rreq = sftp_find_request(pktin = sftp_recv());	assert(rreq == req);	canonname = fxp_realpath_recv(pktin, rreq);	if (!canonname)	    return fullname;	       /* even that failed; give up */	/*	 * We have a canonical name for all but the last path	 * component. Concatenate the last component and return.	 */	returnname = dupcat(canonname,			    canonname[strlen(canonname) - 1] ==			    '/' ? "" : "/", fullname + i + 1, NULL);	sfree(fullname);	sfree(canonname);	return returnname;    }}/* * Return a pointer to the portion of str that comes after the last * slash (or backslash or colon, if `local' is TRUE). */static char *stripslashes(char *str, int local){    char *p;    if (local) {        p = strchr(str, ':');        if (p) str = p+1;    }    p = strrchr(str, '/');    if (p) str = p+1;    if (local) {	p = strrchr(str, '\\');	if (p) str = p+1;    }    return str;}/* ---------------------------------------------------------------------- * Actual sftp commands. */struct sftp_command {    char **words;    int nwords, wordssize;    int (*obey) (struct sftp_command *);	/* returns <0 to quit */};int sftp_cmd_null(struct sftp_command *cmd){    return 1;			       /* success */}int sftp_cmd_unknown(struct sftp_command *cmd){    printf("psftp: unknown command \"%s\"\n", cmd->words[0]);    return 0;			       /* failure */}int sftp_cmd_quit(struct sftp_command *cmd){    return -1;}/* * List a directory. If no arguments are given, list pwd; otherwise * list the directory given in words[1]. */static int sftp_ls_compare(const void *av, const void *bv){    const struct fxp_name *const *a = (const struct fxp_name *const *) av;    const struct fxp_name *const *b = (const struct fxp_name *const *) bv;    return strcmp((*a)->filename, (*b)->filename);}int sftp_cmd_ls(struct sftp_command *cmd){    struct fxp_handle *dirh;    struct fxp_names *names;    struct fxp_name **ournames;    int nnames, namesize;    char *dir, *cdir;    struct sftp_packet *pktin;    struct sftp_request *req, *rreq;    int i;    if (back == NULL) {	printf("psftp: not connected to a host; use \"open host.name\"\n");	return 0;    }    if (cmd->nwords < 2)	dir = ".";    else	dir = cmd->words[1];    cdir = canonify(dir);    if (!cdir) {	printf("%s: %s\n", dir, fxp_error());	return 0;    }    printf("Listing directory %s\n", cdir);    sftp_register(req = fxp_opendir_send(cdir));    rreq = sftp_find_request(pktin = sftp_recv());    assert(rreq == req);    dirh = fxp_opendir_recv(pktin, rreq);    if (dirh == NULL) {	printf("Unable to open %s: %s\n", dir, fxp_error());    } else {	nnames = namesize = 0;	ournames = NULL;	while (1) {	    sftp_register(req = fxp_readdir_send(dirh));	    rreq = sftp_find_request(pktin = sftp_recv());	    assert(rreq == req);	    names = fxp_readdir_recv(pktin, rreq);	    if (names == NULL) {		if (fxp_error_type() == SSH_FX_EOF)		    break;		printf("Reading directory %s: %s\n", dir, fxp_error());		break;	    }	    if (names->nnames == 0) {		fxp_free_names(names);		break;	    }	    if (nnames + names->nnames >= namesize) {		namesize += names->nnames + 128;		ournames = sresize(ournames, namesize, struct fxp_name *);	    }	    for (i = 0; i < names->nnames; i++)		ournames[nnames++] = fxp_dup_name(&names->names[i]);	    fxp_free_names(names);	}	sftp_register(req = fxp_close_send(dirh));	rreq = sftp_find_request(pktin = sftp_recv());	assert(rreq == req);	fxp_close_recv(pktin, rreq);	/*	 * Now we have our filenames. Sort them by actual file	 * name, and then output the longname parts.	 */	qsort(ournames, nnames, sizeof(*ournames), sftp_ls_compare);	/*	 * And print them.	 */	for (i = 0; i < nnames; i++) {	    printf("%s\n", ournames[i]->longname);	    fxp_free_name(ournames[i]);	}	sfree(ournames);    }    sfree(cdir);    return 1;}/* * Change directories. We do this by canonifying the new name, then * trying to OPENDIR it. Only if that succeeds do we set the new pwd. */int sftp_cmd_cd(struct sftp_command *cmd){    struct fxp_handle *dirh;    struct sftp_packet *pktin;    struct sftp_request *req, *rreq;    char *dir;    if (back == NULL) {	printf("psftp: not connected to a host; use \"open host.name\"\n");	return 0;    }    if (cmd->nwords < 2)	dir = dupstr(homedir);    else	dir = canonify(cmd->words[1]);    if (!dir) {	printf("%s: %s\n", dir, fxp_error());	return 0;    }    sftp_register(req = fxp_opendir_send(dir));    rreq = sftp_find_request(pktin = sftp_recv());    assert(rreq == req);    dirh = fxp_opendir_recv(pktin, rreq);    if (!dirh) {	printf("Directory %s: %s\n", dir, fxp_error());	sfree(dir);	return 0;    }    sftp_register(req = fxp_close_send(dirh));    rreq = sftp_find_request(pktin = sftp_recv());    assert(rreq == req);    fxp_close_recv(pktin, rreq);    sfree(pwd);    pwd = dir;    printf("Remote directory is now %s\n", pwd);    return 1;}/* * Print current directory. Easy as pie. */int sftp_cmd_pwd(struct sftp_command *cmd){    if (back == NULL) {	printf("psftp: not connected to a host; use \"open host.name\"\n");	return 0;    }    printf("Remote directory is %s\n", pwd);    return 1;}/* * Get a file and save it at the local end. We have two very * similar commands here: `get' and `reget', which differ in that * `reget' checks for the existence of the destination file and * starts from where a previous aborted transfer left off. */int sftp_general_get(struct sftp_command *cmd, int restart){    struct fxp_handle *fh;    struct sftp_packet *pktin;    struct sftp_request *req, *rreq;    struct fxp_xfer *xfer;    char *fname, *outfname;    uint64 offset;    FILE *fp;    int ret;    if (back == NULL) {	printf("psftp: not connected to a host; use \"open host.name\"\n");	return 0;    }    if (cmd->nwords < 2) {	printf("get: expects a filename\n");	return 0;    }    fname = canonify(cmd->words[1]);    if (!fname) {	printf("%s: %s\n", cmd->words[1], fxp_error());	return 0;    }    outfname = (cmd->nwords == 2 ?		stripslashes(cmd->words[1], 0) : cmd->words[2]);    sftp_register(req = fxp_open_send(fname, SSH_FXF_READ));    rreq = sftp_find_request(pktin = sftp_recv());    assert(rreq == req);    fh = fxp_open_recv(pktin, rreq);    if (!fh) {	printf("%s: %s\n", fname, fxp_error());	sfree(fname);	return 0;    }    if (restart) {	fp = fopen(outfname, "rb+");    } else {	fp = fopen(outfname, "wb");    }    if (!fp) {	printf("local: unable to open %s\n", outfname);	sftp_register(req = fxp_close_send(fh));	rreq = sftp_find_request(pktin = sftp_recv());	assert(rreq == req);	fxp_close_recv(pktin, rreq);	sfree(fname);	return 0;    }    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);    } else {	offset = uint64_make(0, 0);    }    printf("remote:%s => local:%s\n", fname, outfname);    /*     * FIXME: we can use FXP_FSTAT here to get the file size, and     * thus put up a progress bar.     */    ret = 1;    xfer = xfer_download_init(fh, offset);    while (!xfer_done(xfer)) {	void *vbuf;	int ret, len;	int wpos, wlen;	xfer_download_queue(xfer);	pktin = sftp_recv();	ret = xfer_download_gotpkt(xfer, pktin);	if (ret < 0) {            printf("error while reading: %s\n", fxp_error());            ret = 0;	}	while (xfer_download_data(xfer, &vbuf, &len)) {	    unsigned char *buf = (unsigned char *)vbuf;	    wpos = 0;	    while (wpos < len) {		wlen = fwrite(buf + wpos, 1, len - wpos, fp);		if (wlen <= 0) {		    printf("error while writing local file\n");		    ret = 0;		    xfer_set_error(xfer);		}		wpos += wlen;	    }	    if (wpos < len) {	       /* we had an error */		ret = 0;		xfer_set_error(xfer);	    }	    sfree(vbuf);	}    }    xfer_cleanup(xfer);    fclose(fp);    sftp_register(req = fxp_close_send(fh));    rreq = sftp_find_request(pktin = sftp_recv());    assert(rreq == req);    fxp_close_recv(pktin, rreq);    sfree(fname);    return ret;}int sftp_cmd_get(struct sftp_command *cmd){    return sftp_general_get(cmd, 0);}int sftp_cmd_reget(struct sftp_command *cmd){    return sftp_general_get(cmd, 1);}/* * Send a file and store it at the remote end. We have two very * similar commands here: `put' and `reput', which differ in that * `reput' checks for the existence of the destination file and * starts from where a previous aborted transfer left off. */int sftp_general_put(struct sftp_command *cmd, int restart){    struct fxp_handle *fh;    struct fxp_xfer *xfer;    char *fname, *origoutfname, *outfname;    struct sftp_packet *pktin;    struct sftp_request *req, *rreq;    uint64 offset;    FILE *fp;    int ret, err, eof;    if (back == NULL) {	printf("psftp: not connected to a host; use \"open host.name\"\n");	return 0;    }    if (cmd->nwords < 2) {	printf("put: expects a filename\n");	return 0;    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -