sftp: Read the data directly into packet->payload
to avoid allocate 16KB buffer from stack and one memory copy Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com> Reviewed-by: Jakub Jelen <jjelen@redhat.com> Change-Id: Ib71cb5834b7810bf9791e13c58571e2b9fa5bca1
Этот коммит содержится в:
родитель
3ab17e3fbd
Коммит
3b29e2ad4c
32
src/sftp.c
32
src/sftp.c
@ -58,7 +58,6 @@
|
|||||||
|
|
||||||
/* Buffer size maximum is 256M */
|
/* Buffer size maximum is 256M */
|
||||||
#define SFTP_PACKET_SIZE_MAX 0x10000000
|
#define SFTP_PACKET_SIZE_MAX 0x10000000
|
||||||
#define SFTP_BUFFER_SIZE_MAX 16384
|
|
||||||
|
|
||||||
struct sftp_ext_struct {
|
struct sftp_ext_struct {
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
@ -427,7 +426,8 @@ ssize_t sftp_packet_write(sftp_session sftp, uint8_t type, ssh_buffer payload)
|
|||||||
|
|
||||||
sftp_packet sftp_packet_read(sftp_session sftp)
|
sftp_packet sftp_packet_read(sftp_session sftp)
|
||||||
{
|
{
|
||||||
uint8_t buffer[SFTP_BUFFER_SIZE_MAX];
|
uint8_t tmpbuf[4];
|
||||||
|
uint8_t *buffer = NULL;
|
||||||
sftp_packet packet = sftp->read_packet;
|
sftp_packet packet = sftp->read_packet;
|
||||||
uint32_t size;
|
uint32_t size;
|
||||||
int nread;
|
int nread;
|
||||||
@ -461,7 +461,7 @@ sftp_packet sftp_packet_read(sftp_session sftp)
|
|||||||
int s;
|
int s;
|
||||||
|
|
||||||
// read from channel until 4 bytes have been read or an error occurs
|
// read from channel until 4 bytes have been read or an error occurs
|
||||||
s = ssh_channel_read(sftp->channel, buffer + nread, 4 - nread, 0);
|
s = ssh_channel_read(sftp->channel, tmpbuf + nread, 4 - nread, 0);
|
||||||
if (s < 0) {
|
if (s < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
} else if (s == 0) {
|
} else if (s == 0) {
|
||||||
@ -478,7 +478,7 @@ sftp_packet sftp_packet_read(sftp_session sftp)
|
|||||||
}
|
}
|
||||||
} while (nread < 4);
|
} while (nread < 4);
|
||||||
|
|
||||||
size = PULL_BE_U32(buffer, 0);
|
size = PULL_BE_U32(tmpbuf, 0);
|
||||||
if (size == 0 || size > SFTP_PACKET_SIZE_MAX) {
|
if (size == 0 || size > SFTP_PACKET_SIZE_MAX) {
|
||||||
ssh_set_error(sftp->session, SSH_FATAL, "Invalid sftp packet size!");
|
ssh_set_error(sftp->session, SSH_FATAL, "Invalid sftp packet size!");
|
||||||
sftp_set_error(sftp, SSH_FX_FAILURE);
|
sftp_set_error(sftp, SSH_FX_FAILURE);
|
||||||
@ -486,7 +486,7 @@ sftp_packet sftp_packet_read(sftp_session sftp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
nread = ssh_channel_read(sftp->channel, buffer, 1, 0);
|
nread = ssh_channel_read(sftp->channel, tmpbuf, 1, 0);
|
||||||
if (nread < 0) {
|
if (nread < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
} else if (nread == 0) {
|
} else if (nread == 0) {
|
||||||
@ -501,34 +501,28 @@ sftp_packet sftp_packet_read(sftp_session sftp)
|
|||||||
}
|
}
|
||||||
} while (nread < 1);
|
} while (nread < 1);
|
||||||
|
|
||||||
packet->type = buffer[0];
|
packet->type = tmpbuf[0];
|
||||||
|
|
||||||
/* Remove the packet type size */
|
/* Remove the packet type size */
|
||||||
size -= sizeof(uint8_t);
|
size -= sizeof(uint8_t);
|
||||||
|
|
||||||
nread = ssh_buffer_allocate_size(packet->payload, size);
|
/* Allocate the receive buffer from payload */
|
||||||
if (nread < 0) {
|
buffer = ssh_buffer_allocate(packet->payload, size);
|
||||||
|
if (buffer == NULL) {
|
||||||
ssh_set_error_oom(sftp->session);
|
ssh_set_error_oom(sftp->session);
|
||||||
sftp_set_error(sftp, SSH_FX_FAILURE);
|
sftp_set_error(sftp, SSH_FX_FAILURE);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
while (size > 0 && size < SFTP_PACKET_SIZE_MAX) {
|
while (size > 0 && size < SFTP_PACKET_SIZE_MAX) {
|
||||||
nread = ssh_channel_read(sftp->channel,
|
nread = ssh_channel_read(sftp->channel, buffer, size, 0);
|
||||||
buffer,
|
|
||||||
sizeof(buffer) > size ? size : sizeof(buffer),
|
|
||||||
0);
|
|
||||||
if (nread < 0) {
|
if (nread < 0) {
|
||||||
/* TODO: check if there are cases where an error needs to be set here */
|
/* TODO: check if there are cases where an error needs to be set here */
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nread > 0) {
|
if (nread > 0) {
|
||||||
rc = ssh_buffer_add_data(packet->payload, buffer, nread);
|
buffer += nread;
|
||||||
if (rc != 0) {
|
size -= nread;
|
||||||
ssh_set_error_oom(sftp->session);
|
|
||||||
sftp_set_error(sftp, SSH_FX_FAILURE);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
} else { /* nread == 0 */
|
} else { /* nread == 0 */
|
||||||
/* Retry the reading unless the remote was closed */
|
/* Retry the reading unless the remote was closed */
|
||||||
is_eof = ssh_channel_is_eof(sftp->channel);
|
is_eof = ssh_channel_is_eof(sftp->channel);
|
||||||
@ -540,8 +534,6 @@ sftp_packet sftp_packet_read(sftp_session sftp)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size -= nread;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return packet;
|
return packet;
|
||||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user