diff --git a/include/libssh/buffer.h b/include/libssh/buffer.h index dec11739..4a50bcc7 100644 --- a/include/libssh/buffer.h +++ b/include/libssh/buffer.h @@ -23,7 +23,13 @@ #define BUFFER_H_ #include "libssh/libssh.h" -/* Describes a buffer state */ +/* + * Describes a buffer state + * [XXXXXXXXXXXXDATA PAYLOAD XXXXXXXXXXXXXXXXXXXXXXXX] + * ^ ^ ^ ^] + * \_data points\_pos points here \_used points here | / + * here Allocated + */ struct ssh_buffer_struct { char *data; uint32_t used; diff --git a/src/buffer.c b/src/buffer.c index 465f618a..fd07177c 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -293,14 +293,24 @@ int buffer_add_u8(struct ssh_buffer_struct *buffer,uint8_t data){ int buffer_prepend_data(struct ssh_buffer_struct *buffer, const void *data, uint32_t len) { buffer_verify(buffer); - if (buffer->allocated < (buffer->used + len)) { - if (realloc_buffer(buffer, buffer->used + len) < 0) { + + if(len <= buffer->pos){ + /* It's possible to insert data between begin and pos */ + memcpy(buffer->data + (buffer->pos - len), data, len); + buffer->pos -= len; + buffer_verify(buffer); + return 0; + } + /* pos isn't high enough */ + if (buffer->allocated < (buffer->used - buffer->pos + len)) { + if (realloc_buffer(buffer, buffer->used - buffer->pos + len) < 0) { return -1; } } - memmove(buffer->data + len, buffer->data, buffer->used); + memmove(buffer->data + len, buffer->data + buffer->pos, buffer->used - buffer->pos); memcpy(buffer->data, data, len); - buffer->used += len; + buffer->used += len - buffer->pos; + buffer->pos = 0; buffer_verify(buffer); return 0; } diff --git a/tests/unittests/torture_buffer.c b/tests/unittests/torture_buffer.c index 60712a81..5653c4db 100644 --- a/tests/unittests/torture_buffer.c +++ b/tests/unittests/torture_buffer.c @@ -70,6 +70,14 @@ START_TEST (torture_buffer_prepend) buffer_prepend_data(buffer,"aris",4); ck_assert_int_eq(buffer_get_rest_len(buffer),9); ck_assert_int_eq(memcmp(buffer_get_rest(buffer), "arisbcdef", 9), 0); + /* same thing but we add 5 bytes now */ + buffer_get_u32(buffer,&v); + ck_assert_int_eq(buffer_get_rest_len(buffer),5); + ck_assert_int_eq(memcmp(buffer_get_rest(buffer), "bcdef", 5), 0); + buffer_prepend_data(buffer,"12345",5); + ck_assert_int_eq(buffer_get_rest_len(buffer),10); + ck_assert_int_eq(memcmp(buffer_get_rest(buffer), "12345bcdef", 10), 0); + } END_TEST