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

📄 pscp.c

📁 putty
💻 C
📖 第 1 页 / 共 4 页
字号:
    p = strrchr(str, '/');
    if (p) str = p+1;

    if (local) {
	p = strrchr(str, '\\');
	if (p) str = p+1;
    }

    return str;
}

/*
 * Determine whether a string is entirely composed of dots.
 */
static int is_dots(char *str)
{
    return str[strspn(str, ".")] == '\0';
}

/*
 *  Wait for a response from the other side.
 *  Return 0 if ok, -1 if error.
 */
static int response(void)
{
    char ch, resp, rbuf[2048];
    int p;

    if (ssh_scp_recv((unsigned char *) &resp, 1) <= 0)
	bump("Lost connection");

    p = 0;
    switch (resp) {
      case 0:			       /* ok */
	return (0);
      default:
	rbuf[p++] = resp;
	/* fallthrough */
      case 1:			       /* error */
      case 2:			       /* fatal error */
	do {
	    if (ssh_scp_recv((unsigned char *) &ch, 1) <= 0)
		bump("Protocol error: Lost connection");
	    rbuf[p++] = ch;
	} while (p < sizeof(rbuf) && ch != '\n');
	rbuf[p - 1] = '\0';
	if (resp == 1)
	    tell_user(stderr, "%s\n", rbuf);
	else
	    bump("%s", rbuf);
	errs++;
	return (-1);
    }
}

int sftp_recvdata(char *buf, int len)
{
    return ssh_scp_recv((unsigned char *) buf, len);
}
int sftp_senddata(char *buf, int len)
{
    back->send(backhandle, buf, len);
    return 1;
}

/* ----------------------------------------------------------------------
 * sftp-based replacement for the hacky `pscp -ls'.
 */
static int sftp_ls_compare(const void *av, const void *bv)
{
    const struct fxp_name *a = (const struct fxp_name *) av;
    const struct fxp_name *b = (const struct fxp_name *) bv;
    return strcmp(a->filename, b->filename);
}
void scp_sftp_listdir(char *dirname)
{
    struct fxp_handle *dirh;
    struct fxp_names *names;
    struct fxp_name *ournames;
    struct sftp_packet *pktin;
    struct sftp_request *req, *rreq;
    int nnames, namesize;
    int i;

    if (!fxp_init()) {
	tell_user(stderr, "unable to initialise SFTP: %s", fxp_error());
	errs++;
	return;
    }

    printf("Listing directory %s\n", dirname);

    sftp_register(req = fxp_opendir_send(dirname));
    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", dirname, 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", dirname, 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++] = names->names[i];
	    names->nnames = 0;	       /* prevent free_names */
	    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);
    }
}

/* ----------------------------------------------------------------------
 * Helper routines that contain the actual SCP protocol elements,
 * implemented both as SCP1 and SFTP.
 */

static struct scp_sftp_dirstack {
    struct scp_sftp_dirstack *next;
    struct fxp_name *names;
    int namepos, namelen;
    char *dirpath;
    char *wildcard;
    int matched_something;	       /* wildcard match set was non-empty */
} *scp_sftp_dirstack_head;
static char *scp_sftp_remotepath, *scp_sftp_currentname;
static char *scp_sftp_wildcard;
static int scp_sftp_targetisdir, scp_sftp_donethistarget;
static int scp_sftp_preserve, scp_sftp_recursive;
static unsigned long scp_sftp_mtime, scp_sftp_atime;
static int scp_has_times;
static struct fxp_handle *scp_sftp_filehandle;
static struct fxp_xfer *scp_sftp_xfer;
static uint64 scp_sftp_fileoffset;

int scp_source_setup(char *target, int shouldbedir)
{
    if (using_sftp) {
	/*
	 * Find out whether the target filespec is in fact a
	 * directory.
	 */
	struct sftp_packet *pktin;
	struct sftp_request *req, *rreq;
	struct fxp_attrs attrs;
	int ret;

	if (!fxp_init()) {
	    tell_user(stderr, "unable to initialise SFTP: %s", fxp_error());
	    errs++;
	    return 1;
	}

	sftp_register(req = fxp_stat_send(target));
	rreq = sftp_find_request(pktin = sftp_recv());
	assert(rreq == req);
	ret = fxp_stat_recv(pktin, rreq, &attrs);

	if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS))
	    scp_sftp_targetisdir = 0;
	else
	    scp_sftp_targetisdir = (attrs.permissions & 0040000) != 0;

	if (shouldbedir && !scp_sftp_targetisdir) {
	    bump("pscp: remote filespec %s: not a directory\n", target);
	}

	scp_sftp_remotepath = dupstr(target);

	scp_has_times = 0;
    } else {
	(void) response();
    }
    return 0;
}

int scp_send_errmsg(char *str)
{
    if (using_sftp) {
	/* do nothing; we never need to send our errors to the server */
    } else {
	back->send(backhandle, "\001", 1);/* scp protocol error prefix */
	back->send(backhandle, str, strlen(str));
    }
    return 0;			       /* can't fail */
}

int scp_send_filetimes(unsigned long mtime, unsigned long atime)
{
    if (using_sftp) {
	scp_sftp_mtime = mtime;
	scp_sftp_atime = atime;
	scp_has_times = 1;
	return 0;
    } else {
	char buf[80];
	sprintf(buf, "T%lu 0 %lu 0\n", mtime, atime);
	back->send(backhandle, buf, strlen(buf));
	return response();
    }
}

int scp_send_filename(char *name, uint64 size, int modes)
{
    if (using_sftp) {
	char *fullname;
	struct sftp_packet *pktin;
	struct sftp_request *req, *rreq;

	if (scp_sftp_targetisdir) {
	    fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
	} else {
	    fullname = dupstr(scp_sftp_remotepath);
	}

	sftp_register(req = fxp_open_send(fullname, SSH_FXF_WRITE |
					  SSH_FXF_CREAT | SSH_FXF_TRUNC));
	rreq = sftp_find_request(pktin = sftp_recv());
	assert(rreq == req);
	scp_sftp_filehandle = fxp_open_recv(pktin, rreq);

	if (!scp_sftp_filehandle) {
	    tell_user(stderr, "pscp: unable to open %s: %s",
		      fullname, fxp_error());
	    errs++;
	    return 1;
	}
	scp_sftp_fileoffset = uint64_make(0, 0);
	scp_sftp_xfer = xfer_upload_init(scp_sftp_filehandle,
					 scp_sftp_fileoffset);
	sfree(fullname);
	return 0;
    } else {
	char buf[40];
	char sizestr[40];
	uint64_decimal(size, sizestr);
	sprintf(buf, "C%04o %s ", modes, sizestr);
	back->send(backhandle, buf, strlen(buf));
	back->send(backhandle, name, strlen(name));
	back->send(backhandle, "\n", 1);
	return response();
    }
}

int scp_send_filedata(char *data, int len)
{
    if (using_sftp) {
	int ret;
	struct sftp_packet *pktin;

	if (!scp_sftp_filehandle) {
	    return 1;
	}

	while (!xfer_upload_ready(scp_sftp_xfer)) {
	    pktin = sftp_recv();
	    ret = xfer_upload_gotpkt(scp_sftp_xfer, pktin);
	    if (!ret) {
		tell_user(stderr, "error while writing: %s\n", fxp_error());
		errs++;
		return 1;
	    }
	}

	xfer_upload_data(scp_sftp_xfer, data, len);

	scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, len);
	return 0;
    } else {
	int bufsize = back->send(backhandle, data, len);

	/*
	 * If the network transfer is backing up - that is, the
	 * remote site is not accepting data as fast as we can
	 * produce it - then we must loop on network events until
	 * we have space in the buffer again.
	 */
	while (bufsize > MAX_SCP_BUFSIZE) {
	    if (ssh_sftp_loop_iteration() < 0)
		return 1;
	    bufsize = back->sendbuffer(backhandle);
	}

	return 0;
    }
}

int scp_send_finish(void)
{
    if (using_sftp) {
	struct fxp_attrs attrs;
	struct sftp_packet *pktin;
	struct sftp_request *req, *rreq;
	int ret;

	while (!xfer_done(scp_sftp_xfer)) {
	    pktin = sftp_recv();
	    xfer_upload_gotpkt(scp_sftp_xfer, pktin);
	}
	xfer_cleanup(scp_sftp_xfer);

	if (!scp_sftp_filehandle) {
	    return 1;
	}
	if (scp_has_times) {
	    attrs.flags = SSH_FILEXFER_ATTR_ACMODTIME;
	    attrs.atime = scp_sftp_atime;
	    attrs.mtime = scp_sftp_mtime;
	    sftp_register(req = fxp_fsetstat_send(scp_sftp_filehandle, attrs));
	    rreq = sftp_find_request(pktin = sftp_recv());
	    assert(rreq == req);
	    ret = fxp_fsetstat_recv(pktin, rreq);
	    if (!ret) {
		tell_user(stderr, "unable to set file times: %s\n", fxp_error());
		errs++;
	    }
	}
	sftp_register(req = fxp_close_send(scp_sftp_filehandle));
	rreq = sftp_find_request(pktin = sftp_recv());
	assert(rreq == req);
	fxp_close_recv(pktin, rreq);
	scp_has_times = 0;
	return 0;
    } else {
	back->send(backhandle, "", 1);
	return response();
    }
}

char *scp_save_remotepath(void)
{
    if (using_sftp)
	return scp_sftp_remotepath;
    else
	return NULL;
}

void scp_restore_remotepath(char *data)
{
    if (using_sftp)
	scp_sftp_remotepath = data;
}

int scp_send_dirname(char *name, int modes)
{
    if (using_sftp) {
	char *fullname;
	char const *err;
	struct fxp_attrs attrs;
	struct sftp_packet *pktin;
	struct sftp_request *req, *rreq;
	int ret;

	if (scp_sftp_targetisdir) {
	    fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
	} else {
	    fullname = dupstr(scp_sftp_remotepath);
	}

	/*
	 * We don't worry about whether we managed to create the
	 * directory, because if it exists already it's OK just to
	 * use it. Instead, we will stat it afterwards, and if it
	 * exists and is a directory we will assume we were either
	 * successful or it didn't matter.
	 */
	sftp_register(req = fxp_mkdir_send(fullname));
	rreq = sftp_find_request(pktin = sftp_recv());
	assert(rreq == req);
	ret = fxp_mkdir_recv(pktin, rreq);

	if (!ret)
	    err = fxp_error();
	else
	    err = "server reported no error";

	sftp_register(req = fxp_stat_send(fullname));
	rreq = sftp_find_request(pktin = sftp_recv());
	assert(rreq == req);
	ret = fxp_stat_recv(pktin, rreq, &attrs);

	if (!ret || !(attrs.flags & SSH_FILEXFER_ATTR_PERMISSIONS) ||
	    !(attrs.permissions & 0040000)) {
	    tell_user(stderr, "unable to create directory %s: %s",
		      fullname, err);
	    errs++;
	    return 1;
	}

	scp_sftp_remotepath = fullname;

	return 0;
    } else {
	char buf[40];
	sprintf(buf, "D%04o 0 ", modes);
	back->send(backhandle, buf, strlen(buf));
	back->send(backhandle, name, strlen(name));
	back->send(backhandle, "\n", 1);
	return response();
    }
}

int scp_send_enddir(void)
{
    if (using_sftp) {
	sfree(scp_sftp_remotepath);
	return 0;
    } else {
	back->send(backhandle, "E\n", 2);
	return response();
    }
}

/*
 * Yes, I know; I have an scp_sink_setup _and_ an scp_sink_init.
 * That's bad. The difference is that scp_sink_setup is called once
 * right at the start, whereas scp_sink_init is called to
 * initialise every level of recursion in the protocol.
 */
int scp_sink_setup(char *source, int preserve, int recursive)
{
    if (using_sftp) {
	char *newsource;

	if (!fxp_init()) {
	    tell_user(stderr, "unable to initialise SFTP: %s", fxp_error());
	    errs++;
	    return 1;
	}
	/*
	 * It's possible that the source string we've been given
	 * contains a wildcard. If so, we must split the directory
	 * away from the wildcard itself (throwing an error if any
	 * wildcardness comes before the final slash) and arrange
	 * things so that a dirstack entry will be set up.
	 */
	newsource = snewn(1+strlen(source), char);
	if (!wc_unescape(newsource, source)) {
	    /* Yes, here we go; it's a wildcard. Bah. */
	    char *dupsource, *lastpart, *dirpart, *wildcard;
	    dupsource = dupstr(source);
	    lastpart = stripslashes(dupsource, 0);
	    wildcard = dupstr(lastpart);
	    *lastpart = '\0';
	    if (*dupsource && dupsource[1]) {
		/*
		 * The remains of dupsource are at least two
		 * characters long, meaning the pathname wasn't
		 * empty or just `/'. Hence, we remove the trailing
		 * slash.
		 */
		lastpart[-1] = '\0';
	    } else if (!*dupsource) {
		/*
		 * The remains of dupsource are _empty_ - the whole
		 * pathname was a wildcard. Hence we need to
		 * replace it with ".".
		 */
		sfree(dupsource);
		dupsource = dupstr(".");
	    }

	    /*
	     * Now we have separated our string into dupsource (the
	     * directory part) and wildcard. Both of these will
	     * need freeing at some point. Next step is to remove
	     * wildcard escapes from the directory part, throwing
	     * an error if it contains a real wildcard.
	     */
	    dirpart = snewn(1+strlen(dupsource), char);
	    if (!wc_unescape(dirpart, dupsource)) {
		tell_user(stderr, "%s: multiple-level wildcards unsupported",
			  source);
		errs++;
		sfree(dirpart);
		sfree(wildcard);
		sfree(dupsource);
		return 1;
	    }

	    /*
	     * Now we have dirpart (unescaped, ie a valid remote
	     * path), and wildcard (a wildcard). This will be
	     * sufficient to arrange a dirstack entry.
	     */
	    scp_sftp_remotepath = dirpart;
	    scp_sftp_wildcard = wildcard;
	    sfree(dupsource);
	} else {
	    scp_sftp_remotepath = newsource;
	    scp_sftp_wildcard = NULL;
	}
	scp_sftp_preserve = preserve;
	scp_sftp_recursive = recursive;
	scp_sftp_donethistarget = 0;
	scp_sftp_dirstack_head = NULL;
    }
    return 0;
}

int scp_sink_init(void)
{
    if (!using_sftp) {
	back->send(backhandle, "", 1);
    }
    return 0;
}

#define SCP_SINK_FILE   1
#define SCP_SINK_DIR    2
#define SCP_SINK_ENDDIR 3
#define SCP_SINK_RETRY  4	       /* not an action; just try again */
struct scp_sink_action {
    int action;			       /* FILE, DIR, ENDDIR */
    char *buf;			       /* will need freeing after use */
    char *name;			       /* filename or dirname (not ENDDIR) */
    int mode;			       /* access mode (not ENDDIR) */
    uint64 size;		       /* file size (not ENDDIR) */
    int settime;		       /* 1 if atime and mtime are filled */
    unsigned long atime, mtime;	       /* access times for the file */
};

int scp_get_sink_action(struct scp_sink_action *act)
{
    if (using_sftp) {
	char *fname;
	int must_free_fname;
	struct fxp_attrs attrs;
	struct sftp_packet *pktin;
	struct sftp_request *req, *rreq;
	int ret;

	if (!scp_sftp_dirstack_head) {
	    if (!scp_sftp_donethistarget) {
		/*
		 * Simple case: we are only dealing with one file.
		 */
		fname = scp_sftp_remotepath;
		must_free_fname = 0;

⌨️ 快捷键说明

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