]> git.ipfire.org Git - thirdparty/util-linux.git/blame - lib/buffer.c
lib/buffer: make sure buffer without data is zero terminated [asan]
[thirdparty/util-linux.git] / lib / buffer.c
CommitLineData
3836cd2d
KZ
1/*
2 * No copyright is claimed. This code is in the public domain; do with
3 * it what you wish.
4 *
5 * Written by Karel Zak <kzak@redhat.com>
6 */
0a993981 7#include "buffer.h"
9ea47344 8#include "mbsalign.h"
0a993981
KZ
9
10void ul_buffer_reset_data(struct ul_buffer *buf)
11{
12 if (buf->begin)
13 buf->begin[0] = '\0';
14 buf->end = buf->begin;
68463f5a
KZ
15
16 if (buf->ptrs && buf->nptrs)
17 memset(buf->ptrs, 0, buf->nptrs * sizeof(char *));
0a993981
KZ
18}
19
20void ul_buffer_free_data(struct ul_buffer *buf)
21{
22 assert(buf);
23
24 free(buf->begin);
25 buf->begin = NULL;
26 buf->end = NULL;
27 buf->sz = 0;
f55be401
KZ
28
29 free(buf->ptrs);
30 buf->ptrs = NULL;
31 buf->nptrs = 0;
9ea47344
KZ
32
33 free(buf->encoded);
34 buf->encoded = NULL;
35 buf->encoded_sz = 0;
0a993981
KZ
36}
37
38void ul_buffer_set_chunksize(struct ul_buffer *buf, size_t sz)
39{
40 buf->chunksize = sz;
41}
42
43int ul_buffer_is_empty(struct ul_buffer *buf)
44{
45 return buf->begin == buf->end;
46}
47
f55be401
KZ
48int ul_buffer_save_pointer(struct ul_buffer *buf, unsigned short ptr_idx)
49{
50 if (ptr_idx >= buf->nptrs) {
51 char **tmp = realloc(buf->ptrs, (ptr_idx + 1) * sizeof(char *));
52
53 if (!tmp)
54 return -EINVAL;
55 buf->ptrs = tmp;
56 buf->nptrs = ptr_idx + 1;
57 }
58
59 buf->ptrs[ptr_idx] = buf->end;
60 return 0;
61}
62
63
64char *ul_buffer_get_pointer(struct ul_buffer *buf, unsigned short ptr_idx)
65{
66 if (ptr_idx < buf->nptrs)
67 return buf->ptrs[ptr_idx];
68 return NULL;
69}
70
9ea47344 71/* returns length from begin to the pointer */
f55be401
KZ
72size_t ul_buffer_get_pointer_length(struct ul_buffer *buf, unsigned short ptr_idx)
73{
74 char *ptr = ul_buffer_get_pointer(buf, ptr_idx);
75
9ea47344 76 if (ptr && ptr > buf->begin)
f55be401
KZ
77 return ptr - buf->begin;
78 return 0;
79}
80
9ea47344
KZ
81/* returns width of data in safe encoding (from the begin to the pointer) */
82size_t ul_buffer_get_safe_pointer_width(struct ul_buffer *buf, unsigned short ptr_idx)
83{
84 size_t len = ul_buffer_get_pointer_length(buf, ptr_idx);
85
86 if (!len)
87 return 0;
88
89 return mbs_safe_nwidth(buf->begin, len, NULL);
90}
f55be401 91
0a993981
KZ
92void ul_buffer_refer_string(struct ul_buffer *buf, char *str)
93{
94 if (buf->sz)
95 ul_buffer_free_data(buf);
96 buf->begin = str;
97 buf->sz = str ? strlen(str) : 0;
c76f79e9 98 buf->end = buf->begin ? buf->begin + buf->sz : buf->begin;
0a993981
KZ
99}
100
101int ul_buffer_alloc_data(struct ul_buffer *buf, size_t sz)
102{
103 char *tmp;
104 size_t len = 0;
105
106 assert(buf);
107
108 if (sz <= buf->sz)
109 return 0;
110
111 if (buf->end && buf->begin)
112 len = buf->end - buf->begin;
113
114 if (buf->chunksize)
115 sz = ((sz + buf->chunksize) / buf->chunksize) * buf->chunksize + 1;
116
117 tmp = realloc(buf->begin, sz);
118 if (!tmp)
119 return -ENOMEM;
120
121 buf->begin = tmp;
122 buf->end = buf->begin + len;
123 buf->sz = sz;
124
43485143
KZ
125 memset(buf->end, '\0', sz - len);
126
0a993981
KZ
127 return 0;
128}
129
130int ul_buffer_append_data(struct ul_buffer *buf, const char *data, size_t sz)
131{
132 size_t maxsz = 0;
133
134 if (!buf)
135 return -EINVAL;
136 if (!data || !*data)
137 return 0;
138
139 if (buf->begin && buf->end)
140 maxsz = buf->sz - (buf->end - buf->begin);
141
142 if (maxsz <= sz + 1) {
143 int rc = ul_buffer_alloc_data(buf, buf->sz + sz + 1);
144 if (rc)
145 return rc;
146 }
f831651e
KZ
147 if (!buf->end)
148 return -EINVAL; /* make static analyzers happy */
149
0a993981
KZ
150 memcpy(buf->end, data, sz);
151 buf->end += sz;
152 *buf->end = '\0'; /* make sure it's terminated */
153 return 0;
154}
155
156int ul_buffer_append_string(struct ul_buffer *buf, const char *str)
157{
158 return ul_buffer_append_data(buf, str, strlen(str));
159}
160
161int ul_buffer_append_ntimes(struct ul_buffer *buf, size_t n, const char *str)
162{
163 size_t i;
164 size_t len = strlen(str);
165
166 for (i = 0; len && i < n; i++) {
167 int rc = ul_buffer_append_data(buf, str, len);
168 if (rc)
169 return rc;
170 }
171 return 0;
172}
173
174int ul_buffer_set_data(struct ul_buffer *buf, const char *data, size_t sz)
175{
176 ul_buffer_reset_data(buf);
177 return ul_buffer_append_data(buf, data, sz);
178}
179
9ea47344 180char *ul_buffer_get_data(struct ul_buffer *buf, size_t *sz, size_t *width)
0a993981 181{
f60dc888
KZ
182 if (sz)
183 *sz = buf->end - buf->begin;
9ea47344
KZ
184 if (width)
185 *width = buf->begin && *buf->begin ? mbs_width(buf->begin) : 0;
0a993981
KZ
186 return buf->begin;
187}
188
f60dc888
KZ
189/* size of allocated area (!= size of stored data */
190size_t ul_buffer_get_bufsiz(struct ul_buffer *buf)
191{
192 return buf->sz;
193}
194
9ea47344
KZ
195/* encode data by mbs_safe_encode() to avoid control and non-printable chars */
196char *ul_buffer_get_safe_data(struct ul_buffer *buf, size_t *sz, size_t *width, const char *safechars)
197{
198 char *data = ul_buffer_get_data(buf, NULL, NULL);
199 size_t encsz, wsz = 0;
200 char *res = NULL;
201
202 if (!data)
203 goto nothing;
204
205 encsz = mbs_safe_encode_size(buf->sz) + 1;
206 if (encsz > buf->encoded_sz) {
207 char *tmp = realloc(buf->encoded, encsz);
208 if (!tmp)
209 goto nothing;
210 buf->encoded = tmp;
211 buf->encoded_sz = encsz;
212 }
213
214 res = mbs_safe_encode_to_buffer(data, &wsz, buf->encoded, safechars);
215 if (!res || !wsz || wsz == (size_t) -1)
216 goto nothing;
217
218 if (width)
219 *width = wsz;
220 if (sz)
221 *sz = strlen(res);
222 return res;
223nothing:
224 if (width)
225 *width = 0;
226 if (sz)
227 *sz = 0;
228 return NULL;
229}
230
f60dc888 231
0a993981 232#ifdef TEST_PROGRAM_BUFFER
f55be401
KZ
233
234enum {
235 PTR_AAA = 0,
236 PTR_BBB,
237};
238
0a993981
KZ
239int main(void)
240{
241 struct ul_buffer buf = UL_INIT_BUFFER;
242 char *str;
f60dc888 243 size_t sz = 0;
0a993981
KZ
244
245 ul_buffer_set_chunksize(&buf, 16);
246
247 ul_buffer_append_string(&buf, "AAA");
248 ul_buffer_append_data(&buf, "=", 1);
249 ul_buffer_append_string(&buf, "aaa");
f55be401
KZ
250 ul_buffer_save_pointer(&buf, PTR_AAA);
251
0a993981
KZ
252 ul_buffer_append_data(&buf, ",", 1);
253 ul_buffer_append_string(&buf, "BBB");
254 ul_buffer_append_string(&buf, "=");
255 ul_buffer_append_string(&buf, "bbb");
f55be401 256 ul_buffer_save_pointer(&buf, PTR_BBB);
0a993981 257
9ea47344 258 str = ul_buffer_get_data(&buf, &sz, NULL);
f60dc888 259 printf("data [%zu] '%s'\n", sz, str);
0a993981 260
f55be401
KZ
261 printf(" pointer data len: AAA=%zu, BBB=%zu\n",
262 ul_buffer_get_pointer_length(&buf, PTR_AAA),
263 ul_buffer_get_pointer_length(&buf, PTR_BBB));
9ea47344
KZ
264 printf(" pointer data width: AAA=%zu, BBB=%zu\n",
265 ul_buffer_get_safe_pointer_width(&buf, PTR_AAA),
266 ul_buffer_get_safe_pointer_width(&buf, PTR_BBB));
f55be401 267
0a993981
KZ
268 ul_buffer_reset_data(&buf);
269 ul_buffer_append_string(&buf, "This is really long string to test the buffer function.");
f55be401 270 ul_buffer_save_pointer(&buf, PTR_AAA);
0a993981 271 ul_buffer_append_string(&buf, " YES!");
9ea47344 272 str = ul_buffer_get_data(&buf, &sz, NULL);
f60dc888 273 printf("data [%zu] '%s'\n", sz, str);
f55be401 274 printf(" pointer data len: AAA=%zu\n", ul_buffer_get_pointer_length(&buf, PTR_AAA));
0a993981
KZ
275
276 ul_buffer_free_data(&buf);
277 str = strdup("foo");
278 ul_buffer_refer_string(&buf, str);
279 ul_buffer_append_data(&buf, ",", 1);
280 ul_buffer_append_string(&buf, "bar");
9ea47344 281 str = ul_buffer_get_data(&buf, &sz, NULL);
f60dc888 282 printf("data [%zu] '%s'\n", sz, str);
0a993981
KZ
283
284 ul_buffer_free_data(&buf);
285}
286#endif /* TEST_PROGRAM_BUFFER */