From 562df35e97df116fc3d5f47f623c896cbc92ec1f Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sat, 22 Mar 2025 18:03:31 +0000 Subject: [PATCH] buffer: Create a new generic buffer implementation This is used to hold a dynamically growing buffer. Signed-off-by: Michael Tremer --- Makefile.am | 2 + src/pakfire/buffer.c | 148 +++++++++++++++++++++++++++++++++++++++++++ src/pakfire/buffer.h | 44 +++++++++++++ src/pakfire/repo.c | 1 + src/pakfire/util.h | 8 --- 5 files changed, 195 insertions(+), 8 deletions(-) create mode 100644 src/pakfire/buffer.c create mode 100644 src/pakfire/buffer.h diff --git a/Makefile.am b/Makefile.am index 41455beb..15c89c45 100644 --- a/Makefile.am +++ b/Makefile.am @@ -194,6 +194,8 @@ libpakfire_la_SOURCES = \ src/pakfire/archive_writer.h \ src/pakfire/base64.c \ src/pakfire/base64.h \ + src/pakfire/buffer.c \ + src/pakfire/buffer.h \ src/pakfire/build.c \ src/pakfire/build.h \ src/pakfire/buildservice.c \ diff --git a/src/pakfire/buffer.c b/src/pakfire/buffer.c new file mode 100644 index 00000000..adf3f8d7 --- /dev/null +++ b/src/pakfire/buffer.c @@ -0,0 +1,148 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2025 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#include +#include + +#include +#include + +// Use chunks of 4k size +#define CHUNK_SIZE 4096 + +void pakfire_buffer_free(struct pakfire_buffer* buffer) { + if (buffer->data) + free(buffer->data); +} + +// Rounds up length to the nearest chunk size +static size_t pakfire_buffer_align(size_t length) { + return ((length + CHUNK_SIZE - 1) / CHUNK_SIZE) * CHUNK_SIZE; +} + +static int pakfire_buffer_resize(struct pakfire_buffer* self, size_t length) { + // Check maximum length and refuse to grow + if (self->max_length && (length > self->max_length)) + return -ENOBUFS; + + // Round up to the nearest chunk size + length = pakfire_buffer_align(length); + + // Re-allocate the buffer + self->data = pakfire_realloc(self->data, length); + if (!self->data) + return -errno; + + // Adjust the size + self->length = length; + + return 0; +} + +// Grows the buffer +static int pakfire_buffer_grow(struct pakfire_buffer* self, size_t length) { + // Check if we actually need to grow + if (self->length >= self->used + length) + return 0; + + return pakfire_buffer_resize(self, self->length + length); +} + +// Shrinks the buffer to its minimum size +static int pakfire_buffer_shrink(struct pakfire_buffer* self) { + return pakfire_buffer_resize(self, self->length); +} + +int pakfire_buffer_append(struct pakfire_buffer* self, const char* data, size_t length) { + int r; + + // Check inputs + if (!data) + return -EINVAL; + + // Nothing to do if there is no data + if (!length) + return 0; + + // Grow the buffer + r = pakfire_buffer_grow(self, length); + if (r < 0) + return r; + + // Copy the data + memcpy(self->data + self->used, data, length); + self->used += length; + + return 0; +} + +int pakfire_buffer_append_from_fd(struct pakfire_buffer* self, int fd) { + ssize_t bytes_read = 0; + int r; + + // Read for as long as possible + for (;;) { + // Ensure that we have at least one chunk size available + r = pakfire_buffer_grow(self, CHUNK_SIZE); + if (r < 0) + return r; + + // Read into the buffer + bytes_read = read(fd, self->data + self->used, self->length - self->used); + if (bytes_read < 0) + return bytes_read; + + // We now use more space + self->used += bytes_read; + + // If we have not filled the entire space, we have read everything for now + if (self->used < self->length) + break; + } + + return 0; +} + +int pakfire_buffer_consume(struct pakfire_buffer* self, size_t length) { + // Check if we actually have enough data + if (self->used < length) + return -EINVAL; + + memmove(self->data, self->data + length, self->used - length); + self->used -= length; + + return 0; +} + +size_t pakfire_buffer_find_line(struct pakfire_buffer* self) { + char* p = NULL; + + // Nothing to do if there is no data + if (!self->used) + return 0; + + // Find the byte + p = memchr(self->data, '\n', self->used); + if (!p) + return 0; + + // Return the length + return p - self->data + 1; +} diff --git a/src/pakfire/buffer.h b/src/pakfire/buffer.h new file mode 100644 index 00000000..2a3a8850 --- /dev/null +++ b/src/pakfire/buffer.h @@ -0,0 +1,44 @@ +/*############################################################################# +# # +# Pakfire - The IPFire package management system # +# Copyright (C) 2025 Pakfire development team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +#############################################################################*/ + +#ifndef PAKFIRE_BUFFER_H +#define PAKFIRE_BUFFER_H + +struct pakfire_buffer { + char* data; + size_t length; + + // Actually used data + size_t used; + + // Defines the maximum length this buffer can grow to + size_t max_length; +}; + +void pakfire_buffer_free(struct pakfire_buffer* buffer); + +int pakfire_buffer_append(struct pakfire_buffer* self, const char* data, size_t length); +int pakfire_buffer_append_from_fd(struct pakfire_buffer* self, int fd); + +int pakfire_buffer_consume(struct pakfire_buffer* self, size_t length); + +size_t pakfire_buffer_find_line(struct pakfire_buffer* self); + +#endif /* PAKFIRE_BUFFER_H */ diff --git a/src/pakfire/repo.c b/src/pakfire/repo.c index f087f4e9..3dee18e0 100644 --- a/src/pakfire/repo.c +++ b/src/pakfire/repo.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include diff --git a/src/pakfire/util.h b/src/pakfire/util.h index 06f6dc27..5adb68ca 100644 --- a/src/pakfire/util.h +++ b/src/pakfire/util.h @@ -32,14 +32,6 @@ #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) -/* - A simple buffer object -*/ -struct pakfire_buffer { - char* data; - size_t length; -}; - /* This implementation of realloc frees the original buffer if it could not be resized. -- 2.39.5