summaryrefslogtreecommitdiffstats
path: root/src/basic/iovec-wrapper.c
blob: b335acd1089d0156d8c7ad63005cd432eb8030d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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;
}