Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * mbuf.c
3 : : * Memory buffer operations.
4 : : *
5 : : * Copyright (c) 2005 Marko Kreen
6 : : * All rights reserved.
7 : : *
8 : : * Redistribution and use in source and binary forms, with or without
9 : : * modification, are permitted provided that the following conditions
10 : : * are met:
11 : : * 1. Redistributions of source code must retain the above copyright
12 : : * notice, this list of conditions and the following disclaimer.
13 : : * 2. Redistributions in binary form must reproduce the above copyright
14 : : * notice, this list of conditions and the following disclaimer in the
15 : : * documentation and/or other materials provided with the distribution.
16 : : *
17 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 : : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 : : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 : : * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 : : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 : : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 : : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 : : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 : : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 : : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 : : * SUCH DAMAGE.
28 : : *
29 : : * contrib/pgcrypto/mbuf.c
30 : : */
31 : :
32 : : #include "postgres.h"
33 : :
34 : : #include "mbuf.h"
35 : : #include "px.h"
36 : :
37 : : #define STEP (16*1024)
38 : :
39 : : struct MBuf
40 : : {
41 : : uint8 *data;
42 : : uint8 *data_end;
43 : : uint8 *read_pos;
44 : : uint8 *buf_end;
45 : : bool no_write;
46 : : bool own_data;
47 : : };
48 : :
49 : : int
5421 bruce@momjian.us 50 :CBC 2829 : mbuf_avail(MBuf *mbuf)
51 : : {
6853 52 : 2829 : return mbuf->data_end - mbuf->read_pos;
53 : : }
54 : :
55 : : int
5421 56 : 99 : mbuf_size(MBuf *mbuf)
57 : : {
6853 58 : 99 : return mbuf->data_end - mbuf->data;
59 : : }
60 : :
61 : : int
5421 62 : 273 : mbuf_free(MBuf *mbuf)
63 : : {
6853 64 [ + + ]: 273 : if (mbuf->own_data)
65 : : {
3650 66 : 16 : px_memset(mbuf->data, 0, mbuf->buf_end - mbuf->data);
1297 michael@paquier.xyz 67 : 16 : pfree(mbuf->data);
68 : : }
69 : 273 : pfree(mbuf);
6853 bruce@momjian.us 70 : 273 : return 0;
71 : : }
72 : :
73 : : static void
5421 74 : 401 : prepare_room(MBuf *mbuf, int block_len)
75 : : {
76 : : uint8 *newbuf;
77 : : unsigned newlen;
78 : :
6853 79 [ + + ]: 401 : if (mbuf->data_end + block_len <= mbuf->buf_end)
80 : 395 : return;
81 : :
82 : 6 : newlen = (mbuf->buf_end - mbuf->data)
83 : 6 : + ((block_len + STEP + STEP - 1) & -STEP);
84 : :
1297 michael@paquier.xyz 85 : 6 : newbuf = repalloc(mbuf->data, newlen);
86 : :
6853 bruce@momjian.us 87 : 6 : mbuf->buf_end = newbuf + newlen;
88 : 6 : mbuf->data_end = newbuf + (mbuf->data_end - mbuf->data);
89 : 6 : mbuf->read_pos = newbuf + (mbuf->read_pos - mbuf->data);
90 : 6 : mbuf->data = newbuf;
91 : : }
92 : :
93 : : int
5421 94 : 401 : mbuf_append(MBuf *dst, const uint8 *buf, int len)
95 : : {
6853 96 [ - + ]: 401 : if (dst->no_write)
97 : : {
6853 bruce@momjian.us 98 :UBC 0 : px_debug("mbuf_append: no_write");
99 : 0 : return PXE_BUG;
100 : : }
101 : :
6853 bruce@momjian.us 102 :CBC 401 : prepare_room(dst, len);
103 : :
104 : 401 : memcpy(dst->data_end, buf, len);
105 : 401 : dst->data_end += len;
106 : :
107 : 401 : return 0;
108 : : }
109 : :
110 : : MBuf *
111 : 115 : mbuf_create(int len)
112 : : {
113 : : MBuf *mbuf;
114 : :
115 [ - + ]: 115 : if (!len)
6853 bruce@momjian.us 116 :UBC 0 : len = 8192;
117 : :
1297 michael@paquier.xyz 118 :CBC 115 : mbuf = palloc(sizeof *mbuf);
119 : 115 : mbuf->data = palloc(len);
6853 bruce@momjian.us 120 : 115 : mbuf->buf_end = mbuf->data + len;
121 : 115 : mbuf->data_end = mbuf->data;
122 : 115 : mbuf->read_pos = mbuf->data;
123 : :
6118 tgl@sss.pgh.pa.us 124 : 115 : mbuf->no_write = false;
125 : 115 : mbuf->own_data = true;
126 : :
6853 bruce@momjian.us 127 : 115 : return mbuf;
128 : : }
129 : :
130 : : MBuf *
4473 peter_e@gmx.net 131 : 158 : mbuf_create_from_data(uint8 *data, int len)
132 : : {
133 : : MBuf *mbuf;
134 : :
1297 michael@paquier.xyz 135 : 158 : mbuf = palloc(sizeof *mbuf);
6853 bruce@momjian.us 136 : 158 : mbuf->data = (uint8 *) data;
137 : 158 : mbuf->buf_end = mbuf->data + len;
138 : 158 : mbuf->data_end = mbuf->data + len;
139 : 158 : mbuf->read_pos = mbuf->data;
140 : :
6118 tgl@sss.pgh.pa.us 141 : 158 : mbuf->no_write = true;
142 : 158 : mbuf->own_data = false;
143 : :
6853 bruce@momjian.us 144 : 158 : return mbuf;
145 : : }
146 : :
147 : :
148 : : int
5421 149 : 2692 : mbuf_grab(MBuf *mbuf, int len, uint8 **data_p)
150 : : {
6853 151 [ + + ]: 2692 : if (len > mbuf_avail(mbuf))
152 : 101 : len = mbuf_avail(mbuf);
153 : :
6118 tgl@sss.pgh.pa.us 154 : 2692 : mbuf->no_write = true;
155 : :
6853 bruce@momjian.us 156 : 2692 : *data_p = mbuf->read_pos;
157 : 2692 : mbuf->read_pos += len;
158 : 2692 : return len;
159 : : }
160 : :
161 : : int
5421 162 : 99 : mbuf_steal_data(MBuf *mbuf, uint8 **data_p)
163 : : {
6756 164 : 99 : int len = mbuf_size(mbuf);
165 : :
6118 tgl@sss.pgh.pa.us 166 : 99 : mbuf->no_write = true;
167 : 99 : mbuf->own_data = false;
168 : :
6853 bruce@momjian.us 169 : 99 : *data_p = mbuf->data;
170 : :
171 : 99 : mbuf->data = mbuf->data_end = mbuf->read_pos = mbuf->buf_end = NULL;
172 : :
173 : 99 : return len;
174 : : }
175 : :
176 : : /*
177 : : * PullFilter
178 : : */
179 : :
180 : : struct PullFilter
181 : : {
182 : : PullFilter *src;
183 : : const PullFilterOps *op;
184 : : int buflen;
185 : : uint8 *buf;
186 : : int pos;
187 : : void *priv;
188 : : };
189 : :
190 : : int
5421 191 : 809 : pullf_create(PullFilter **pf_p, const PullFilterOps *op, void *init_arg, PullFilter *src)
192 : : {
193 : : PullFilter *pf;
194 : : void *priv;
195 : : int res;
196 : :
6853 197 [ + + ]: 809 : if (op->init != NULL)
198 : : {
199 : 225 : res = op->init(&priv, init_arg, src);
200 [ - + ]: 225 : if (res < 0)
6853 bruce@momjian.us 201 :UBC 0 : return res;
202 : : }
203 : : else
204 : : {
6853 bruce@momjian.us 205 :CBC 584 : priv = init_arg;
206 : 584 : res = 0;
207 : : }
208 : :
1297 michael@paquier.xyz 209 : 809 : pf = palloc0(sizeof(*pf));
6853 bruce@momjian.us 210 : 809 : pf->buflen = res;
211 : 809 : pf->op = op;
212 : 809 : pf->priv = priv;
213 : 809 : pf->src = src;
214 [ + + ]: 809 : if (pf->buflen > 0)
215 : : {
1297 michael@paquier.xyz 216 : 76 : pf->buf = palloc(pf->buflen);
6853 bruce@momjian.us 217 : 76 : pf->pos = 0;
218 : : }
219 : : else
220 : : {
221 : 733 : pf->buf = NULL;
222 : 733 : pf->pos = 0;
223 : : }
224 : 809 : *pf_p = pf;
225 : 809 : return 0;
226 : : }
227 : :
228 : : void
5421 229 : 809 : pullf_free(PullFilter *pf)
230 : : {
6853 231 [ + + ]: 809 : if (pf->op->free)
232 : 545 : pf->op->free(pf->priv);
233 : :
234 [ + + ]: 809 : if (pf->buf)
235 : : {
3650 236 : 76 : px_memset(pf->buf, 0, pf->buflen);
1297 michael@paquier.xyz 237 : 76 : pfree(pf->buf);
238 : : }
239 : :
3650 bruce@momjian.us 240 : 809 : px_memset(pf, 0, sizeof(*pf));
1297 michael@paquier.xyz 241 : 809 : pfree(pf);
6853 bruce@momjian.us 242 : 809 : }
243 : :
244 : : /* may return less data than asked, 0 means eof */
245 : : int
5421 246 : 7522 : pullf_read(PullFilter *pf, int len, uint8 **data_p)
247 : : {
248 : : int res;
249 : :
6853 250 [ + + ]: 7522 : if (pf->op->pull)
251 : : {
252 [ + + + + ]: 6813 : if (pf->buflen && len > pf->buflen)
253 : 23 : len = pf->buflen;
254 : 6813 : res = pf->op->pull(pf->priv, pf->src, len, data_p,
255 : : pf->buf, pf->buflen);
256 : : }
257 : : else
258 : 709 : res = pullf_read(pf->src, len, data_p);
259 : 7522 : return res;
260 : : }
261 : :
262 : : int
5421 263 : 1898 : pullf_read_max(PullFilter *pf, int len, uint8 **data_p, uint8 *tmpbuf)
264 : : {
265 : : int res,
266 : : total;
267 : : uint8 *tmp;
268 : :
6853 269 : 1898 : res = pullf_read(pf, len, data_p);
270 [ + + + + ]: 1898 : if (res <= 0 || res == len)
271 : 1891 : return res;
272 : :
273 : : /* read was shorter, use tmpbuf */
274 : 7 : memcpy(tmpbuf, *data_p, res);
275 : 7 : *data_p = tmpbuf;
276 : 7 : len -= res;
277 : 7 : total = res;
278 : :
6756 279 [ + + ]: 8 : while (len > 0)
280 : : {
6853 281 : 7 : res = pullf_read(pf, len, &tmp);
282 [ - + ]: 7 : if (res < 0)
283 : : {
284 : : /* so the caller must clear only on success */
3650 bruce@momjian.us 285 :UBC 0 : px_memset(tmpbuf, 0, total);
6853 286 : 0 : return res;
287 : : }
6853 bruce@momjian.us 288 [ + + ]:CBC 7 : if (res == 0)
289 : 6 : break;
290 : 1 : memcpy(tmpbuf + total, tmp, res);
291 : 1 : total += res;
3359 noah@leadboat.com 292 : 1 : len -= res;
293 : : }
6853 bruce@momjian.us 294 : 7 : return total;
295 : : }
296 : :
297 : : /*
298 : : * caller wants exactly len bytes and don't bother with references
299 : : */
300 : : int
5421 301 : 1636 : pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
302 : : {
303 : : int res;
304 : : uint8 *p;
305 : :
6853 306 : 1636 : res = pullf_read_max(src, len, &p, dst);
307 [ - + ]: 1636 : if (res < 0)
6853 bruce@momjian.us 308 :UBC 0 : return res;
6853 bruce@momjian.us 309 [ + + ]:CBC 1636 : if (res != len)
310 : : {
311 : 2 : px_debug("pullf_read_fixed: need=%d got=%d", len, res);
3254 noah@leadboat.com 312 : 2 : return PXE_PGP_CORRUPT_DATA;
313 : : }
6853 bruce@momjian.us 314 [ + - ]: 1634 : if (p != dst)
315 : 1634 : memcpy(dst, p, len);
316 : 1634 : return 0;
317 : : }
318 : :
319 : : /*
320 : : * read from MBuf
321 : : */
322 : : static int
5421 323 : 2656 : pull_from_mbuf(void *arg, PullFilter *src, int len,
324 : : uint8 **data_p, uint8 *buf, int buflen)
325 : : {
6853 326 : 2656 : MBuf *mbuf = arg;
327 : :
328 : 2656 : return mbuf_grab(mbuf, len, data_p);
329 : : }
330 : :
331 : : static const struct PullFilterOps mbuf_reader = {
332 : : NULL, pull_from_mbuf, NULL
333 : : };
334 : :
335 : : int
5421 336 : 116 : pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src)
337 : : {
6853 338 : 116 : return pullf_create(mp_p, &mbuf_reader, src, NULL);
339 : : }
340 : :
341 : :
342 : : /*
343 : : * PushFilter
344 : : */
345 : :
346 : : struct PushFilter
347 : : {
348 : : PushFilter *next;
349 : : const PushFilterOps *op;
350 : : int block_size;
351 : : uint8 *buf;
352 : : int pos;
353 : : void *priv;
354 : : };
355 : :
356 : : int
5421 357 : 193 : pushf_create(PushFilter **mp_p, const PushFilterOps *op, void *init_arg, PushFilter *next)
358 : : {
359 : : PushFilter *mp;
360 : : void *priv;
361 : : int res;
362 : :
6853 363 [ + + ]: 193 : if (op->init != NULL)
364 : : {
365 : 155 : res = op->init(next, init_arg, &priv);
366 [ - + ]: 155 : if (res < 0)
6853 bruce@momjian.us 367 :UBC 0 : return res;
368 : : }
369 : : else
370 : : {
6853 bruce@momjian.us 371 :CBC 38 : priv = init_arg;
372 : 38 : res = 0;
373 : : }
374 : :
1297 michael@paquier.xyz 375 : 193 : mp = palloc0(sizeof(*mp));
6853 bruce@momjian.us 376 : 193 : mp->block_size = res;
377 : 193 : mp->op = op;
378 : 193 : mp->priv = priv;
379 : 193 : mp->next = next;
380 [ + + ]: 193 : if (mp->block_size > 0)
381 : : {
1297 michael@paquier.xyz 382 : 120 : mp->buf = palloc(mp->block_size);
6853 bruce@momjian.us 383 : 120 : mp->pos = 0;
384 : : }
385 : : else
386 : : {
387 : 73 : mp->buf = NULL;
388 : 73 : mp->pos = 0;
389 : : }
390 : 193 : *mp_p = mp;
391 : 193 : return 0;
392 : : }
393 : :
394 : : void
5421 395 : 193 : pushf_free(PushFilter *mp)
396 : : {
6853 397 [ + + ]: 193 : if (mp->op->free)
398 : 155 : mp->op->free(mp->priv);
399 : :
400 [ + + ]: 193 : if (mp->buf)
401 : : {
3650 402 : 120 : px_memset(mp->buf, 0, mp->block_size);
1297 michael@paquier.xyz 403 : 120 : pfree(mp->buf);
404 : : }
405 : :
3650 bruce@momjian.us 406 : 193 : px_memset(mp, 0, sizeof(*mp));
1297 michael@paquier.xyz 407 : 193 : pfree(mp);
6853 bruce@momjian.us 408 : 193 : }
409 : :
410 : : void
5421 411 : 36 : pushf_free_all(PushFilter *mp)
412 : : {
413 : : PushFilter *tmp;
414 : :
6853 415 [ + + ]: 223 : while (mp)
416 : : {
417 : 187 : tmp = mp->next;
418 : 187 : pushf_free(mp);
419 : 187 : mp = tmp;
420 : : }
421 : 36 : }
422 : :
423 : : static int
5421 424 : 487 : wrap_process(PushFilter *mp, const uint8 *data, int len)
425 : : {
426 : : int res;
427 : :
6853 428 [ + - ]: 487 : if (mp->op->push != NULL)
429 : 487 : res = mp->op->push(mp->next, mp->priv, data, len);
430 : : else
6853 bruce@momjian.us 431 :UBC 0 : res = pushf_write(mp->next, data, len);
6853 bruce@momjian.us 432 [ - + ]:CBC 487 : if (res > 0)
6853 bruce@momjian.us 433 :UBC 0 : return PXE_BUG;
6853 bruce@momjian.us 434 :CBC 487 : return res;
435 : : }
436 : :
437 : : /* consumes all data, returns len on success */
438 : : int
5421 439 : 757 : pushf_write(PushFilter *mp, const uint8 *data, int len)
440 : : {
441 : : int need,
442 : : res;
443 : :
444 : : /*
445 : : * no buffering
446 : : */
6853 447 [ + + ]: 757 : if (mp->block_size <= 0)
448 : 347 : return wrap_process(mp, data, len);
449 : :
450 : : /*
451 : : * try to empty buffer
452 : : */
453 : 410 : need = mp->block_size - mp->pos;
454 [ + - ]: 410 : if (need > 0)
455 : : {
456 [ + + ]: 410 : if (len < need)
457 : : {
458 : 397 : memcpy(mp->buf + mp->pos, data, len);
459 : 397 : mp->pos += len;
460 : 397 : return 0;
461 : : }
462 : 13 : memcpy(mp->buf + mp->pos, data, need);
463 : 13 : len -= need;
464 : 13 : data += need;
465 : : }
466 : :
467 : : /*
468 : : * buffer full, process
469 : : */
470 : 13 : res = wrap_process(mp, mp->buf, mp->block_size);
471 [ - + ]: 13 : if (res < 0)
6853 bruce@momjian.us 472 :UBC 0 : return res;
6853 bruce@momjian.us 473 :CBC 13 : mp->pos = 0;
474 : :
475 : : /*
476 : : * now process directly from data
477 : : */
478 [ + + ]: 20 : while (len > 0)
479 : : {
480 [ + + ]: 19 : if (len > mp->block_size)
481 : : {
482 : 7 : res = wrap_process(mp, data, mp->block_size);
483 [ - + ]: 7 : if (res < 0)
6853 bruce@momjian.us 484 :UBC 0 : return res;
6853 bruce@momjian.us 485 :CBC 7 : data += mp->block_size;
486 : 7 : len -= mp->block_size;
487 : : }
488 : : else
489 : : {
490 : 12 : memcpy(mp->buf, data, len);
491 : 12 : mp->pos += len;
492 : 12 : break;
493 : : }
494 : : }
495 : 13 : return 0;
496 : : }
497 : :
498 : : int
5421 499 : 42 : pushf_flush(PushFilter *mp)
500 : : {
501 : : int res;
502 : :
6853 503 [ + + ]: 241 : while (mp)
504 : : {
505 [ + + ]: 199 : if (mp->block_size > 0)
506 : : {
507 : 120 : res = wrap_process(mp, mp->buf, mp->pos);
508 [ - + ]: 120 : if (res < 0)
6853 bruce@momjian.us 509 :UBC 0 : return res;
510 : : }
511 : :
6853 bruce@momjian.us 512 [ + + ]:CBC 199 : if (mp->op->flush)
513 : : {
514 : 119 : res = mp->op->flush(mp->next, mp->priv);
515 [ - + ]: 119 : if (res < 0)
6853 bruce@momjian.us 516 :UBC 0 : return res;
517 : : }
518 : :
6853 bruce@momjian.us 519 :CBC 199 : mp = mp->next;
520 : : }
521 : 42 : return 0;
522 : : }
523 : :
524 : :
525 : : /*
526 : : * write to MBuf
527 : : */
528 : : static int
5421 529 : 196 : push_into_mbuf(PushFilter *next, void *arg, const uint8 *data, int len)
530 : : {
6853 531 : 196 : int res = 0;
532 : 196 : MBuf *mbuf = arg;
533 : :
534 [ + - ]: 196 : if (len > 0)
535 : 196 : res = mbuf_append(mbuf, data, len);
536 : 196 : return res < 0 ? res : 0;
537 : : }
538 : :
539 : : static const struct PushFilterOps mbuf_filter = {
540 : : NULL, push_into_mbuf, NULL, NULL
541 : : };
542 : :
543 : : int
5421 544 : 36 : pushf_create_mbuf_writer(PushFilter **res, MBuf *dst)
545 : : {
6853 546 : 36 : return pushf_create(res, &mbuf_filter, dst, NULL);
547 : : }
|