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:
parent
dbb2c0030a
commit
144b738f31
9
misc.c
9
misc.c
@ -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
1
misc.h
@ -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
71
pscp.c
@ -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
74
psftp.c
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user