iovec-wrapper: rename iovw_append() to iovw_extend()
The naming is consistent with strv_extend(). This also - introduces tiny iovw_extend_iov() wrapper, - refuse when the source and target points to the same object, - check the final count before extending in iovw_extend_iovw().
This commit is contained in:
+47
-29
@@ -74,7 +74,7 @@ int iovw_consume(struct iovec_wrapper *iovw, void *data, size_t len) {
|
||||
return r;
|
||||
}
|
||||
|
||||
int iovw_append(struct iovec_wrapper *iovw, const void *data, size_t len) {
|
||||
int iovw_extend(struct iovec_wrapper *iovw, const void *data, size_t len) {
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
@@ -85,6 +85,52 @@ int iovw_append(struct iovec_wrapper *iovw, const void *data, size_t len) {
|
||||
return iovw_consume(iovw, c, len);
|
||||
}
|
||||
|
||||
int iovw_extend_iov(struct iovec_wrapper *iovw, const struct iovec *iov) {
|
||||
assert(iovw);
|
||||
|
||||
if (!iovec_is_set(iov))
|
||||
return 0;
|
||||
|
||||
return iovw_extend(iovw, iov->iov_base, iov->iov_len);
|
||||
}
|
||||
|
||||
int iovw_extend_iovw(struct iovec_wrapper *iovw, const struct iovec_wrapper *source) {
|
||||
int r;
|
||||
|
||||
assert(iovw);
|
||||
|
||||
/* This duplicates the source and merges it into the iovw. */
|
||||
|
||||
if (iovw_isempty(source))
|
||||
return 0;
|
||||
|
||||
/* iovw->iovec will be reallocated in the loop below, hence source cannot point to the same object. */
|
||||
if (iovw == source)
|
||||
return -EINVAL;
|
||||
|
||||
if (iovw->count > SIZE_MAX - source->count)
|
||||
return -E2BIG;
|
||||
if (iovw->count + source->count > IOV_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
size_t original_count = iovw->count;
|
||||
|
||||
FOREACH_ARRAY(iovec, source->iovec, source->count) {
|
||||
r = iovw_extend_iov(iovw, iovec);
|
||||
if (r < 0)
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
for (size_t i = original_count; i < iovw->count; i++)
|
||||
iovec_done(iovw->iovec + i);
|
||||
|
||||
iovw->count = original_count;
|
||||
return r;
|
||||
}
|
||||
|
||||
int iovw_put_string_field_full(struct iovec_wrapper *iovw, bool replace, const char *field, const char *value) {
|
||||
_cleanup_free_ char *x = NULL;
|
||||
int r;
|
||||
@@ -147,34 +193,6 @@ size_t iovw_size(const struct iovec_wrapper *iovw) {
|
||||
return iovec_total_size(iovw->iovec, iovw->count);
|
||||
}
|
||||
|
||||
int iovw_append_iovw(struct iovec_wrapper *target, const struct iovec_wrapper *source) {
|
||||
int r;
|
||||
|
||||
assert(target);
|
||||
|
||||
/* This duplicates the source and merges it into the target. */
|
||||
|
||||
if (iovw_isempty(source))
|
||||
return 0;
|
||||
|
||||
size_t original_count = target->count;
|
||||
|
||||
FOREACH_ARRAY(iovec, source->iovec, source->count) {
|
||||
r = iovw_append(target, iovec->iov_base, iovec->iov_len);
|
||||
if (r < 0)
|
||||
goto rollback;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
rollback:
|
||||
for (size_t i = original_count; i < target->count; i++)
|
||||
iovec_done(target->iovec + i);
|
||||
|
||||
target->count = original_count;
|
||||
return r;
|
||||
}
|
||||
|
||||
int iovw_concat(const struct iovec_wrapper *iovw, struct iovec *ret) {
|
||||
assert(iovw);
|
||||
assert(ret);
|
||||
|
||||
@@ -18,7 +18,9 @@ static inline bool iovw_equal(const struct iovec_wrapper *a, const struct iovec_
|
||||
|
||||
int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len);
|
||||
int iovw_consume(struct iovec_wrapper *iovw, void *data, size_t len);
|
||||
int iovw_append(struct iovec_wrapper *iovw, const void *data, size_t len);
|
||||
int iovw_extend(struct iovec_wrapper *iovw, const void *data, size_t len);
|
||||
int iovw_extend_iov(struct iovec_wrapper *iovw, const struct iovec *iov);
|
||||
int iovw_extend_iovw(struct iovec_wrapper *iovw, const struct iovec_wrapper *source);
|
||||
|
||||
static inline bool iovw_isempty(const struct iovec_wrapper *iovw) {
|
||||
return !iovw || iovw->count == 0;
|
||||
@@ -37,6 +39,5 @@ int iovw_put_string_fieldf_full(struct iovec_wrapper *iovw, bool replace, const
|
||||
int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value);
|
||||
void iovw_rebase(struct iovec_wrapper *iovw, void *old, void *new);
|
||||
size_t iovw_size(const struct iovec_wrapper *iovw);
|
||||
int iovw_append_iovw(struct iovec_wrapper *target, const struct iovec_wrapper *source);
|
||||
int iovw_concat(const struct iovec_wrapper *iovw, struct iovec *ret);
|
||||
char* iovw_to_cstring(const struct iovec_wrapper *iovw);
|
||||
|
||||
@@ -50,7 +50,7 @@ int coredump_backtrace(int argc, char *argv[]) {
|
||||
} else {
|
||||
/* The imported iovecs are not supposed to be freed by us so let's copy and merge them at the
|
||||
* end of the array. */
|
||||
r = iovw_append_iovw(&context.iovw, &importer.iovw);
|
||||
r = iovw_extend_iovw(&context.iovw, &importer.iovw);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ static size_t output_callback(char *buf,
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = iovw_append(&context->upload_answer, buf, nmemb);
|
||||
r = iovw_extend(&context->upload_answer, buf, nmemb);
|
||||
if (r < 0) {
|
||||
log_warning("Failed to store server answer (%zu bytes): out of memory", nmemb);
|
||||
return 0; /* Returning < nmemb signals failure */
|
||||
|
||||
@@ -84,18 +84,23 @@ TEST(iovw_put) {
|
||||
ASSERT_EQ(memcmp(iovw.iovec[2].iov_base, "q", 1), 0);
|
||||
}
|
||||
|
||||
TEST(iovw_append) {
|
||||
TEST(iovw_extend) {
|
||||
_cleanup_(iovw_done_free) struct iovec_wrapper iovw = {};
|
||||
|
||||
/* iovw_append copies the data; the wrapper owns the copies. */
|
||||
/* Appending an empty/NULL source is a no-op */
|
||||
ASSERT_OK_ZERO(iovw_extend(&iovw, NULL, 0));
|
||||
ASSERT_OK_ZERO(iovw_extend(&iovw, "foo", 0));
|
||||
ASSERT_EQ(iovw.count, 0U);
|
||||
|
||||
/* iovw_extend() copies the data; the wrapper owns the copies. */
|
||||
char buf[4] = { 'o', 'n', 'e', '\0' };
|
||||
ASSERT_OK(iovw_append(&iovw, buf, 3));
|
||||
ASSERT_OK(iovw_extend(&iovw, buf, 3));
|
||||
ASSERT_EQ(iovw.count, 1U);
|
||||
ASSERT_EQ(iovw.iovec[0].iov_len, 3U);
|
||||
ASSERT_EQ(memcmp(iovw.iovec[0].iov_base, "one", 3), 0);
|
||||
|
||||
/* Insert with a NUL */
|
||||
ASSERT_OK(iovw_append(&iovw, buf, 4));
|
||||
ASSERT_OK(iovw_extend(&iovw, buf, 4));
|
||||
ASSERT_EQ(iovw.count, 2U);
|
||||
ASSERT_EQ(iovw.iovec[1].iov_len, 4U);
|
||||
ASSERT_EQ(memcmp(iovw.iovec[1].iov_base, "one\0", 4), 0);
|
||||
@@ -105,6 +110,60 @@ TEST(iovw_append) {
|
||||
ASSERT_EQ(memcmp(iovw.iovec[0].iov_base, "one", 3), 0);
|
||||
}
|
||||
|
||||
TEST(iovw_extend_iov) {
|
||||
_cleanup_(iovw_done_free) struct iovec_wrapper iovw = {};
|
||||
|
||||
/* Appending an empty/NULL source is a no-op */
|
||||
ASSERT_OK_ZERO(iovw_extend_iov(&iovw, NULL));
|
||||
ASSERT_OK_ZERO(iovw_extend_iov(&iovw, &(struct iovec) {}));
|
||||
ASSERT_EQ(iovw.count, 0U);
|
||||
|
||||
ASSERT_OK(iovw_extend_iov(&iovw, &IOVEC_MAKE_STRING("aaa")));
|
||||
ASSERT_OK(iovw_extend_iov(&iovw, &IOVEC_MAKE_STRING("bbb")));
|
||||
ASSERT_OK(iovw_extend_iov(&iovw, &IOVEC_MAKE_STRING("ccc")));
|
||||
ASSERT_EQ(iovw.count, 3U);
|
||||
ASSERT_EQ(iovec_memcmp(&iovw.iovec[0], &IOVEC_MAKE_STRING("aaa")), 0);
|
||||
ASSERT_EQ(iovec_memcmp(&iovw.iovec[1], &IOVEC_MAKE_STRING("bbb")), 0);
|
||||
ASSERT_EQ(iovec_memcmp(&iovw.iovec[2], &IOVEC_MAKE_STRING("ccc")), 0);
|
||||
}
|
||||
|
||||
TEST(iovw_extend_iovw) {
|
||||
_cleanup_(iovw_done_free) struct iovec_wrapper target = {};
|
||||
_cleanup_(iovw_done) struct iovec_wrapper source = {};
|
||||
|
||||
/* Appending an empty/NULL source is a no-op */
|
||||
ASSERT_OK_ZERO(iovw_extend_iovw(&target, NULL));
|
||||
ASSERT_OK_ZERO(iovw_extend_iovw(&target, &source));
|
||||
ASSERT_EQ(target.count, 0U);
|
||||
|
||||
ASSERT_OK(iovw_put(&source, (char*) "one", 3));
|
||||
ASSERT_OK(iovw_put(&source, (char*) "twotwo", 6));
|
||||
ASSERT_EQ(source.count, 2U);
|
||||
|
||||
/* Pre-seed target with one entry to check that append adds on top rather than replacing */
|
||||
char *seed = strdup("zero");
|
||||
ASSERT_NOT_NULL(seed);
|
||||
ASSERT_OK(iovw_put(&target, seed, strlen(seed)));
|
||||
|
||||
ASSERT_OK(iovw_extend_iovw(&target, &source));
|
||||
ASSERT_EQ(target.count, 3U);
|
||||
|
||||
/* Appended entries must be fresh copies, not aliases of the source entries */
|
||||
ASSERT_TRUE(target.iovec[1].iov_base != source.iovec[0].iov_base);
|
||||
ASSERT_TRUE(target.iovec[2].iov_base != source.iovec[1].iov_base);
|
||||
|
||||
ASSERT_EQ(target.iovec[1].iov_len, 3U);
|
||||
ASSERT_EQ(memcmp(target.iovec[1].iov_base, "one", 3), 0);
|
||||
ASSERT_EQ(target.iovec[2].iov_len, 6U);
|
||||
ASSERT_EQ(memcmp(target.iovec[2].iov_base, "twotwo", 6), 0);
|
||||
|
||||
/* Source is unchanged */
|
||||
ASSERT_EQ(source.count, 2U);
|
||||
|
||||
/* Cannot pass the same objects */
|
||||
ASSERT_ERROR(iovw_extend_iovw(&target, &target), EINVAL);
|
||||
}
|
||||
|
||||
TEST(iovw_consume) {
|
||||
_cleanup_(iovw_done_free) struct iovec_wrapper iovw = {};
|
||||
|
||||
@@ -245,40 +304,6 @@ TEST(iovw_size) {
|
||||
ASSERT_EQ(iovw_size(&iovw), 12U);
|
||||
}
|
||||
|
||||
TEST(iovw_append_iovw) {
|
||||
_cleanup_(iovw_done_free) struct iovec_wrapper target = {};
|
||||
_cleanup_(iovw_done) struct iovec_wrapper source = {};
|
||||
|
||||
/* Appending an empty/NULL source is a no-op */
|
||||
ASSERT_OK_ZERO(iovw_append_iovw(&target, NULL));
|
||||
ASSERT_OK_ZERO(iovw_append_iovw(&target, &source));
|
||||
ASSERT_EQ(target.count, 0U);
|
||||
|
||||
ASSERT_OK(iovw_put(&source, (char*) "one", 3));
|
||||
ASSERT_OK(iovw_put(&source, (char*) "twotwo", 6));
|
||||
ASSERT_EQ(source.count, 2U);
|
||||
|
||||
/* Pre-seed target with one entry to check that append adds on top rather than replacing */
|
||||
char *seed = strdup("zero");
|
||||
ASSERT_NOT_NULL(seed);
|
||||
ASSERT_OK(iovw_put(&target, seed, strlen(seed)));
|
||||
|
||||
ASSERT_OK(iovw_append_iovw(&target, &source));
|
||||
ASSERT_EQ(target.count, 3U);
|
||||
|
||||
/* Appended entries must be fresh copies, not aliases of the source entries */
|
||||
ASSERT_TRUE(target.iovec[1].iov_base != source.iovec[0].iov_base);
|
||||
ASSERT_TRUE(target.iovec[2].iov_base != source.iovec[1].iov_base);
|
||||
|
||||
ASSERT_EQ(target.iovec[1].iov_len, 3U);
|
||||
ASSERT_EQ(memcmp(target.iovec[1].iov_base, "one", 3), 0);
|
||||
ASSERT_EQ(target.iovec[2].iov_len, 6U);
|
||||
ASSERT_EQ(memcmp(target.iovec[2].iov_base, "twotwo", 6), 0);
|
||||
|
||||
/* Source is unchanged */
|
||||
ASSERT_EQ(source.count, 2U);
|
||||
}
|
||||
|
||||
TEST(iovw_concat) {
|
||||
_cleanup_(iovw_done) struct iovec_wrapper iovw = {};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user