1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00: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

9
misc.c
View File

@ -813,6 +813,15 @@ bool bufchain_try_fetch_consume(bufchain *ch, void *data, int len)
}
}
int bufchain_fetch_consume_up_to(bufchain *ch, void *data, int len)
{
if (len > ch->buffersize)
len = ch->buffersize;
if (len)
bufchain_fetch_consume(ch, data, len);
return len;
}
/* ----------------------------------------------------------------------
* Sanitise terminal output that we have reason not to trust, e.g.
* because it appears in the login banner or password prompt from a

1
misc.h
View File

@ -106,6 +106,7 @@ void bufchain_consume(bufchain *ch, int len);
void bufchain_fetch(bufchain *ch, void *data, int len);
void bufchain_fetch_consume(bufchain *ch, void *data, int len);
bool bufchain_try_fetch_consume(bufchain *ch, void *data, int len);
int bufchain_fetch_consume_up_to(bufchain *ch, void *data, int len);
void sanitise_term_data(bufchain *out, const void *vdata, int len);

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;

74
psftp.c
View File

@ -2490,16 +2490,9 @@ void agent_schedule_callback(void (*callback)(void *, void *, int),
* 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 */
static int psftp_output(Seat *seat, bool is_stderr,
const void *data, int datalen)
static bufchain received_data;
static int psftp_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.
@ -2511,32 +2504,7 @@ static int psftp_output(Seat *seat, bool is_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;
}
bufchain_add(&received_data, data, len);
return 0;
}
@ -2556,34 +2524,16 @@ static bool psftp_eof(Seat *seat)
bool sftp_recvdata(char *buf, int len)
{
outptr = (unsigned char *) buf;
outlen = len;
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;