diff options
Diffstat (limited to 'src/basic/iovec-wrapper.c')
-rw-r--r-- | src/basic/iovec-wrapper.c | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/basic/iovec-wrapper.c b/src/basic/iovec-wrapper.c new file mode 100644 index 0000000..b335acd --- /dev/null +++ b/src/basic/iovec-wrapper.c @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "iovec-util.h" +#include "iovec-wrapper.h" +#include "string-util.h" + +struct iovec_wrapper *iovw_new(void) { + return new0(struct iovec_wrapper, 1); +} + +void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors) { + assert(iovw); + + if (free_vectors) + for (size_t i = 0; i < iovw->count; i++) + free(iovw->iovec[i].iov_base); + + iovw->iovec = mfree(iovw->iovec); + iovw->count = 0; +} + +struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw) { + if (!iovw) + return NULL; + + iovw_free_contents(iovw, /* free_vectors= */ true); + return mfree(iovw); +} + +struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw) { + if (!iovw) + return NULL; + + iovw_free_contents(iovw, /* free_vectors= */ false); + return mfree(iovw); +} + +int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len) { + assert(iovw); + + if (len == 0) + return 0; + + assert(data); + + if (iovw->count >= IOV_MAX) + return -E2BIG; + + if (!GREEDY_REALLOC(iovw->iovec, iovw->count + 1)) + return -ENOMEM; + + iovw->iovec[iovw->count++] = IOVEC_MAKE(data, len); + return 0; +} + +int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value) { + _cleanup_free_ char *x = NULL; + int r; + + assert(iovw); + + x = strjoin(field, value); + if (!x) + return -ENOMEM; + + r = iovw_put(iovw, x, strlen(x)); + if (r >= 0) + TAKE_PTR(x); + + return r; +} + +int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value) { + _cleanup_free_ _unused_ char *free_ptr = value; + + return iovw_put_string_field(iovw, field, value); +} + +void iovw_rebase(struct iovec_wrapper *iovw, void *old, void *new) { + assert(iovw); + + FOREACH_ARRAY(i, iovw->iovec, iovw->count) { + assert(i->iov_base >= old); + i->iov_base = (uint8_t*) i->iov_base - (uint8_t*) old + (uint8_t*) new; + } +} + +size_t iovw_size(const struct iovec_wrapper *iovw) { + if (!iovw) + return 0; + + return iovec_total_size(iovw->iovec, iovw->count); +} + +int iovw_append(struct iovec_wrapper *target, const struct iovec_wrapper *source) { + size_t original_count; + int r; + + assert(target); + + /* This duplicates the source and merges it into the target. */ + + if (iovw_isempty(source)) + return 0; + + original_count = target->count; + + FOREACH_ARRAY(iovec, source->iovec, source->count) { + void *dup; + + dup = memdup(iovec->iov_base, iovec->iov_len); + if (!dup) { + r = -ENOMEM; + goto rollback; + } + + r = iovw_consume(target, dup, iovec->iov_len); + if (r < 0) + goto rollback; + } + + return 0; + +rollback: + for (size_t i = original_count; i < target->count; i++) + free(target->iovec[i].iov_base); + + target->count = original_count; + return r; +} |