1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-01 03:22:48 -05:00

pscp, psftp: use a bufchain in ssh_scp_recv.

The ad-hoc code that received data from the SCP or SFTP server
predated even not-very-modern conveniences such as bufchain, and was
quite horrible and cumbersome.

Particularly nasty was the part where ssh_scp_recv set a _global_
pointer variable to the buffer it was in the middle of writing to, and
then recursed and expected a callback to use that pointer. That caused
clang-analyzer to grumble at me, in a particular case where the output
buffer was in the ultimate caller's stack frame; even though I'm
confident the code _worked_, I can't blame clang for being unhappy!

So now we do things the modern and much simpler way: the callback when
data comes in just puts it on a bufchain, and the top-level
ssh_scp_recv repeatedly waits until data arrives in the bufchain and
then copies it to the output buffer.
This commit is contained in:
Simon Tatham
2018-12-01 09:56:32 +00:00
parent dbb2c0030a
commit 144b738f31
4 changed files with 36 additions and 119 deletions

71
pscp.c
View File

@ -144,16 +144,9 @@ void agent_schedule_callback(void (*callback)(void *, void *, int),
* 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 */
static int pscp_output(Seat *seat, bool is_stderr,
const void *data, int datalen)
static bufchain received_data;
static int pscp_output(Seat *seat, bool is_stderr, const void *data, int len)
{
unsigned char *p = (unsigned char *) data;
unsigned len = (unsigned) datalen;
/*
* stderr data is just spouted to local stderr and otherwise
* ignored.
@ -165,26 +158,7 @@ static int pscp_output(Seat *seat, bool is_stderr,
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;
}
bufchain_add(&received_data, data, len);
return 0;
}
static bool pscp_eof(Seat *seat)
@ -201,36 +175,19 @@ static bool pscp_eof(Seat *seat)
}
return false;
}
static bool ssh_scp_recv(void *buf, int len)
static bool ssh_scp_recv(void *vbuf, int len)
{
outptr = buf;
outlen = len;
char *buf = (char *)vbuf;
while (len > 0) {
while (bufchain_size(&received_data) == 0) {
if (backend_exitcode(backend) >= 0 ||
ssh_sftp_loop_iteration() < 0)
return false; /* doom */
}
/*
* 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 true;
}
while (outlen > 0) {
if (backend_exitcode(backend) >= 0 || ssh_sftp_loop_iteration() < 0)
return false; /* doom */
int got = bufchain_fetch_consume_up_to(&received_data, buf, len);
buf += got;
len -= got;
}
return true;