Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions libutils/buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <platform.h>
#include <alloc.h>
#include <buffer.h>
#include <file_lib.h> /* FullRead() */
#include <refcount.h>
#include <misc_lib.h>
#ifdef WITH_PCRE2
Expand Down Expand Up @@ -304,6 +305,29 @@ void BufferAppend(Buffer *buffer, const char *bytes, size_t length)
}
}

bool BufferAppendFileContent(Buffer *buffer, int fd)
{
assert(buffer != NULL);

char bytes[4096];
ssize_t n_read;
do
{
n_read = FullRead(fd, bytes, sizeof(bytes));
if (n_read < 0)
{
return false;
}

BufferAppend(buffer, bytes, (size_t) n_read);

/* FullRead() reads until the requested amount or end of file, so a
* short read means we have it all. */
} while ((size_t) n_read == sizeof(bytes));

return true;
}

void BufferAppendChar(Buffer *buffer, char byte)
{
assert(buffer != NULL);
Expand Down
9 changes: 9 additions & 0 deletions libutils/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,15 @@ void BufferAppendChar(Buffer *buffer, char byte);
void BufferAppendF(Buffer *buffer, const char *format, ...);
void BufferAppendString(Buffer *buffer, const char *str);

/**
@brief Appends everything that can be read from a file descriptor.
@param buffer Structure to operate on.
@param fd File descriptor to read from, until end of file.
@return Whether everything was read successfully. On failure, errno is set by
read(2) and the buffer contains whatever was read before the failure.
*/
bool BufferAppendFileContent(Buffer *buffer, int fd);

/**
@brief Stores complex data on the buffer.

Expand Down
50 changes: 50 additions & 0 deletions tests/unit/buffer_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string.h>
#include <cmockery.h>
#include <buffer.h>
#include <file_lib.h>

static void test_createBuffer(void)
{
Expand Down Expand Up @@ -599,6 +600,54 @@ static void test_vprintf(void)
free(char0int0char1double0);
}

static void test_appendFileContent(void)
{
/* Sizes around the 4096 byte chunk BufferAppendFileContent() reads in, so
* that both the short-read and the exact-multiple cases are covered. */
const size_t sizes[] = { 0, 1, 4095, 4096, 4097, 8192, 100000 };

for (size_t i = 0; i < sizeof(sizes) / sizeof(*sizes); i++)
{
const size_t size = sizes[i];
char *expected = xmalloc(size + 1);
for (size_t j = 0; j < size; j++)
{
expected[j] = 'a' + (j % 26);
}
expected[size] = '\0';

char filename[] = "/tmp/buffer_test_XXXXXX";
int fd = mkstemp(filename);
assert_true(fd >= 0);
assert_int_equal(size, FullWrite(fd, expected, size));
assert_int_equal(0, lseek(fd, 0, SEEK_SET));

Buffer *buffer = BufferNew();
BufferAppendString(buffer, "prefix:");
assert_true(BufferAppendFileContent(buffer, fd));
assert_int_equal(strlen("prefix:") + size, BufferSize(buffer));
assert_int_equal(0, memcmp(BufferData(buffer) + strlen("prefix:"), expected, size));

BufferDestroy(buffer);
close(fd);
unlink(filename);
free(expected);
}

/* Reading from a descriptor which is not open for reading fails. */
char filename[] = "/tmp/buffer_test_XXXXXX";
int fd = mkstemp(filename);
assert_true(fd >= 0);
close(fd);
int wronly_fd = open(filename, O_WRONLY);
assert_true(wronly_fd >= 0);
Buffer *buffer = BufferNew();
assert_false(BufferAppendFileContent(buffer, wronly_fd));
BufferDestroy(buffer);
close(wronly_fd);
unlink(filename);
}

int main()
{
PRINT_TEST_BANNER();
Expand All @@ -611,6 +660,7 @@ int main()
unit_test(test_copyCompareBuffer),
unit_test(test_setBuffer),
unit_test(test_appendBuffer),
unit_test(test_appendFileContent),
unit_test(test_append_boundaries),
unit_test(test_printf),
unit_test(test_vprintf)
Expand Down
Loading