Age Owner 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
5050 bruce 50 CBC 2829 : mbuf_avail(MBuf *mbuf)
51 : {
6482 52 2829 : return mbuf->data_end - mbuf->read_pos;
53 : }
54 :
55 : int
5050 56 99 : mbuf_size(MBuf *mbuf)
57 : {
6482 58 99 : return mbuf->data_end - mbuf->data;
59 : }
60 :
6482 bruce 61 ECB : int
5050 bruce 62 GIC 273 : mbuf_free(MBuf *mbuf)
6482 bruce 63 ECB : {
6482 bruce 64 CBC 273 : if (mbuf->own_data)
65 : {
3279 bruce 66 GIC 16 : px_memset(mbuf->data, 0, mbuf->buf_end - mbuf->data);
926 michael 67 16 : pfree(mbuf->data);
6482 bruce 68 ECB : }
926 michael 69 GIC 273 : pfree(mbuf);
6482 bruce 70 273 : return 0;
71 : }
72 :
6482 bruce 73 ECB : static void
5050 bruce 74 CBC 401 : prepare_room(MBuf *mbuf, int block_len)
75 : {
6482 bruce 76 ECB : uint8 *newbuf;
77 : unsigned newlen;
78 :
6482 bruce 79 CBC 401 : if (mbuf->data_end + block_len <= mbuf->buf_end)
6482 bruce 80 GIC 395 : return;
6482 bruce 81 ECB :
6482 bruce 82 CBC 6 : newlen = (mbuf->buf_end - mbuf->data)
83 6 : + ((block_len + STEP + STEP - 1) & -STEP);
6482 bruce 84 ECB :
926 michael 85 GIC 6 : newbuf = repalloc(mbuf->data, newlen);
86 :
6482 bruce 87 6 : mbuf->buf_end = newbuf + newlen;
6482 bruce 88 CBC 6 : mbuf->data_end = newbuf + (mbuf->data_end - mbuf->data);
6482 bruce 89 GIC 6 : mbuf->read_pos = newbuf + (mbuf->read_pos - mbuf->data);
6482 bruce 90 CBC 6 : mbuf->data = newbuf;
91 : }
6482 bruce 92 EUB :
93 : int
5050 bruce 94 GIC 401 : mbuf_append(MBuf *dst, const uint8 *buf, int len)
95 : {
6482 bruce 96 CBC 401 : if (dst->no_write)
97 : {
6482 bruce 98 LBC 0 : px_debug("mbuf_append: no_write");
99 0 : return PXE_BUG;
100 : }
6482 bruce 101 ECB :
6482 bruce 102 GIC 401 : prepare_room(dst, len);
103 :
104 401 : memcpy(dst->data_end, buf, len);
6482 bruce 105 CBC 401 : dst->data_end += len;
106 :
6482 bruce 107 GIC 401 : return 0;
108 : }
6482 bruce 109 ECB :
6482 bruce 110 EUB : MBuf *
6482 bruce 111 GIC 115 : mbuf_create(int len)
6482 bruce 112 ECB : {
113 : MBuf *mbuf;
114 :
6482 bruce 115 CBC 115 : if (!len)
6482 bruce 116 LBC 0 : len = 8192;
117 :
926 michael 118 CBC 115 : mbuf = palloc(sizeof *mbuf);
119 115 : mbuf->data = palloc(len);
6482 bruce 120 GIC 115 : mbuf->buf_end = mbuf->data + len;
6482 bruce 121 CBC 115 : mbuf->data_end = mbuf->data;
6482 bruce 122 GIC 115 : mbuf->read_pos = mbuf->data;
123 :
5747 tgl 124 115 : mbuf->no_write = false;
5747 tgl 125 CBC 115 : mbuf->own_data = true;
126 :
6482 bruce 127 GIC 115 : return mbuf;
128 : }
6482 bruce 129 ECB :
130 : MBuf *
4102 peter_e 131 CBC 158 : mbuf_create_from_data(uint8 *data, int len)
6482 bruce 132 ECB : {
133 : MBuf *mbuf;
134 :
926 michael 135 CBC 158 : mbuf = palloc(sizeof *mbuf);
6482 bruce 136 158 : mbuf->data = (uint8 *) data;
6482 bruce 137 GIC 158 : mbuf->buf_end = mbuf->data + len;
6482 bruce 138 CBC 158 : mbuf->data_end = mbuf->data + len;
6482 bruce 139 GIC 158 : mbuf->read_pos = mbuf->data;
140 :
5747 tgl 141 158 : mbuf->no_write = true;
142 158 : mbuf->own_data = false;
6482 bruce 143 ECB :
6482 bruce 144 GIC 158 : return mbuf;
6482 bruce 145 ECB : }
146 :
147 :
148 : int
5050 bruce 149 GIC 2692 : mbuf_grab(MBuf *mbuf, int len, uint8 **data_p)
6482 bruce 150 ECB : {
6482 bruce 151 CBC 2692 : if (len > mbuf_avail(mbuf))
152 101 : len = mbuf_avail(mbuf);
153 :
5747 tgl 154 GIC 2692 : mbuf->no_write = true;
155 :
6482 bruce 156 CBC 2692 : *data_p = mbuf->read_pos;
6482 bruce 157 GIC 2692 : mbuf->read_pos += len;
6482 bruce 158 CBC 2692 : return len;
159 : }
6482 bruce 160 ECB :
161 : int
5050 bruce 162 GIC 99 : mbuf_steal_data(MBuf *mbuf, uint8 **data_p)
163 : {
6385 164 99 : int len = mbuf_size(mbuf);
165 :
5747 tgl 166 99 : mbuf->no_write = true;
167 99 : mbuf->own_data = false;
168 :
6482 bruce 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
6482 bruce 178 ECB : */
179 :
180 : struct PullFilter
181 : {
182 : PullFilter *src;
183 : const PullFilterOps *op;
184 : int buflen;
185 : uint8 *buf;
186 : int pos;
187 : void *priv;
6482 bruce 188 EUB : };
189 :
190 : int
5050 bruce 191 GIC 809 : pullf_create(PullFilter **pf_p, const PullFilterOps *op, void *init_arg, PullFilter *src)
6482 bruce 192 ECB : {
6385 193 : PullFilter *pf;
194 : void *priv;
195 : int res;
6482 196 :
6482 bruce 197 CBC 809 : if (op->init != NULL)
6482 bruce 198 ECB : {
6482 bruce 199 CBC 225 : res = op->init(&priv, init_arg, src);
200 225 : if (res < 0)
6482 bruce 201 LBC 0 : return res;
202 : }
6482 bruce 203 ECB : else
204 : {
6482 bruce 205 GIC 584 : priv = init_arg;
206 584 : res = 0;
207 : }
6482 bruce 208 ECB :
926 michael 209 CBC 809 : pf = palloc0(sizeof(*pf));
6482 bruce 210 GIC 809 : pf->buflen = res;
6482 bruce 211 CBC 809 : pf->op = op;
212 809 : pf->priv = priv;
6482 bruce 213 GIC 809 : pf->src = src;
214 809 : if (pf->buflen > 0)
215 : {
926 michael 216 CBC 76 : pf->buf = palloc(pf->buflen);
6482 bruce 217 GIC 76 : pf->pos = 0;
6482 bruce 218 ECB : }
219 : else
220 : {
6482 bruce 221 CBC 733 : pf->buf = NULL;
6482 bruce 222 GIC 733 : pf->pos = 0;
6482 bruce 223 ECB : }
6482 bruce 224 CBC 809 : *pf_p = pf;
6482 bruce 225 GIC 809 : return 0;
226 : }
6482 bruce 227 ECB :
228 : void
5050 bruce 229 CBC 809 : pullf_free(PullFilter *pf)
230 : {
6482 bruce 231 GIC 809 : if (pf->op->free)
232 545 : pf->op->free(pf->priv);
6482 bruce 233 ECB :
6482 bruce 234 GIC 809 : if (pf->buf)
235 : {
3279 236 76 : px_memset(pf->buf, 0, pf->buflen);
926 michael 237 CBC 76 : pfree(pf->buf);
238 : }
6482 bruce 239 ECB :
3279 bruce 240 CBC 809 : px_memset(pf, 0, sizeof(*pf));
926 michael 241 809 : pfree(pf);
6482 bruce 242 GIC 809 : }
243 :
244 : /* may return less data than asked, 0 means eof */
6482 bruce 245 ECB : int
5050 bruce 246 CBC 7522 : pullf_read(PullFilter *pf, int len, uint8 **data_p)
247 : {
248 : int res;
249 :
6482 250 7522 : if (pf->op->pull)
251 : {
6482 bruce 252 GIC 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);
6482 bruce 256 ECB : }
257 : else
6482 bruce 258 CBC 709 : res = pullf_read(pf->src, len, data_p);
6482 bruce 259 GIC 7522 : return res;
260 : }
6482 bruce 261 ECB :
262 : int
5050 bruce 263 CBC 1898 : pullf_read_max(PullFilter *pf, int len, uint8 **data_p, uint8 *tmpbuf)
6482 bruce 264 ECB : {
265 : int res,
6385 266 : total;
267 : uint8 *tmp;
6482 268 :
6482 bruce 269 CBC 1898 : res = pullf_read(pf, len, data_p);
6482 bruce 270 GIC 1898 : if (res <= 0 || res == len)
271 1891 : return res;
6482 bruce 272 EUB :
273 : /* read was shorter, use tmpbuf */
6482 bruce 274 GIC 7 : memcpy(tmpbuf, *data_p, res);
6482 bruce 275 CBC 7 : *data_p = tmpbuf;
276 7 : len -= res;
277 7 : total = res;
6385 bruce 278 ECB :
6385 bruce 279 CBC 8 : while (len > 0)
280 : {
6482 281 7 : res = pullf_read(pf, len, &tmp);
6482 bruce 282 GIC 7 : if (res < 0)
283 : {
284 : /* so the caller must clear only on success */
3279 bruce 285 UIC 0 : px_memset(tmpbuf, 0, total);
6482 286 0 : return res;
287 : }
6482 bruce 288 CBC 7 : if (res == 0)
6482 bruce 289 GIC 6 : break;
290 1 : memcpy(tmpbuf + total, tmp, res);
291 1 : total += res;
2988 noah 292 1 : len -= res;
6482 bruce 293 ECB : }
6482 bruce 294 CBC 7 : return total;
6482 bruce 295 EUB : }
6482 bruce 296 ECB :
297 : /*
2253 heikki.linnakangas 298 : * caller wants exactly len bytes and don't bother with references
6482 bruce 299 : */
300 : int
5050 bruce 301 CBC 1636 : pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
6482 bruce 302 ECB : {
6385 303 : int res;
304 : uint8 *p;
305 :
6482 bruce 306 GIC 1636 : res = pullf_read_max(src, len, &p, dst);
307 1636 : if (res < 0)
6482 bruce 308 UIC 0 : return res;
6482 bruce 309 GIC 1636 : if (res != len)
6482 bruce 310 ECB : {
6482 bruce 311 GIC 2 : px_debug("pullf_read_fixed: need=%d got=%d", len, res);
2883 noah 312 2 : return PXE_PGP_CORRUPT_DATA;
6482 bruce 313 ECB : }
6482 bruce 314 GIC 1634 : if (p != dst)
6482 bruce 315 CBC 1634 : memcpy(dst, p, len);
6482 bruce 316 GIC 1634 : return 0;
317 : }
318 :
319 : /*
320 : * read from MBuf
321 : */
322 : static int
5050 bruce 323 CBC 2656 : pull_from_mbuf(void *arg, PullFilter *src, int len,
324 : uint8 **data_p, uint8 *buf, int buflen)
6482 bruce 325 ECB : {
6482 bruce 326 GIC 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
5050 336 116 : pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src)
337 : {
6482 338 116 : return pullf_create(mp_p, &mbuf_reader, src, NULL);
339 : }
340 :
341 :
342 : /*
343 : * PushFilter
6482 bruce 344 ECB : */
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;
6482 bruce 354 EUB : };
355 :
356 : int
5050 bruce 357 GIC 193 : pushf_create(PushFilter **mp_p, const PushFilterOps *op, void *init_arg, PushFilter *next)
6482 bruce 358 ECB : {
6385 359 : PushFilter *mp;
360 : void *priv;
361 : int res;
6482 362 :
6482 bruce 363 CBC 193 : if (op->init != NULL)
6482 bruce 364 ECB : {
6482 bruce 365 CBC 155 : res = op->init(next, init_arg, &priv);
366 155 : if (res < 0)
6482 bruce 367 LBC 0 : return res;
368 : }
6482 bruce 369 ECB : else
370 : {
6482 bruce 371 GIC 38 : priv = init_arg;
372 38 : res = 0;
373 : }
6482 bruce 374 ECB :
926 michael 375 CBC 193 : mp = palloc0(sizeof(*mp));
6482 bruce 376 GIC 193 : mp->block_size = res;
6482 bruce 377 CBC 193 : mp->op = op;
378 193 : mp->priv = priv;
6482 bruce 379 GIC 193 : mp->next = next;
380 193 : if (mp->block_size > 0)
381 : {
926 michael 382 CBC 120 : mp->buf = palloc(mp->block_size);
6482 bruce 383 GIC 120 : mp->pos = 0;
6482 bruce 384 ECB : }
385 : else
386 : {
6482 bruce 387 CBC 73 : mp->buf = NULL;
6482 bruce 388 GIC 73 : mp->pos = 0;
6482 bruce 389 ECB : }
6482 bruce 390 CBC 193 : *mp_p = mp;
6482 bruce 391 GIC 193 : return 0;
392 : }
6482 bruce 393 ECB :
394 : void
5050 bruce 395 CBC 193 : pushf_free(PushFilter *mp)
396 : {
6482 bruce 397 GIC 193 : if (mp->op->free)
6482 bruce 398 CBC 155 : mp->op->free(mp->priv);
399 :
6482 bruce 400 GIC 193 : if (mp->buf)
401 : {
3279 bruce 402 CBC 120 : px_memset(mp->buf, 0, mp->block_size);
926 michael 403 GIC 120 : pfree(mp->buf);
6482 bruce 404 ECB : }
405 :
3279 bruce 406 CBC 193 : px_memset(mp, 0, sizeof(*mp));
926 michael 407 GIC 193 : pfree(mp);
6482 bruce 408 CBC 193 : }
409 :
410 : void
5050 411 36 : pushf_free_all(PushFilter *mp)
412 : {
413 : PushFilter *tmp;
414 :
6482 415 223 : while (mp)
6482 bruce 416 ECB : {
6482 bruce 417 GIC 187 : tmp = mp->next;
6482 bruce 418 GBC 187 : pushf_free(mp);
6482 bruce 419 CBC 187 : mp = tmp;
6482 bruce 420 EUB : }
6482 bruce 421 CBC 36 : }
422 :
423 : static int
5050 bruce 424 GIC 487 : wrap_process(PushFilter *mp, const uint8 *data, int len)
425 : {
6482 bruce 426 ECB : int res;
427 :
6482 bruce 428 GIC 487 : if (mp->op->push != NULL)
429 487 : res = mp->op->push(mp->next, mp->priv, data, len);
430 : else
6482 bruce 431 UIC 0 : res = pushf_write(mp->next, data, len);
6482 bruce 432 GIC 487 : if (res > 0)
6482 bruce 433 UIC 0 : return PXE_BUG;
6482 bruce 434 CBC 487 : return res;
6482 bruce 435 ECB : }
436 :
437 : /* consumes all data, returns len on success */
438 : int
5050 bruce 439 GIC 757 : pushf_write(PushFilter *mp, const uint8 *data, int len)
6482 bruce 440 ECB : {
441 : int need,
442 : res;
443 :
444 : /*
445 : * no buffering
446 : */
6482 bruce 447 CBC 757 : if (mp->block_size <= 0)
6482 bruce 448 GIC 347 : return wrap_process(mp, data, len);
6482 bruce 449 ECB :
450 : /*
451 : * try to empty buffer
452 : */
6482 bruce 453 GIC 410 : need = mp->block_size - mp->pos;
454 410 : if (need > 0)
455 : {
456 410 : if (len < need)
6482 bruce 457 ECB : {
6482 bruce 458 CBC 397 : memcpy(mp->buf + mp->pos, data, len);
6482 bruce 459 GBC 397 : mp->pos += len;
6482 bruce 460 CBC 397 : return 0;
461 : }
6482 bruce 462 GIC 13 : memcpy(mp->buf + mp->pos, data, need);
463 13 : len -= need;
464 13 : data += need;
6482 bruce 465 ECB : }
466 :
467 : /*
468 : * buffer full, process
469 : */
6482 bruce 470 CBC 13 : res = wrap_process(mp, mp->buf, mp->block_size);
6482 bruce 471 GBC 13 : if (res < 0)
6482 bruce 472 LBC 0 : return res;
6482 bruce 473 CBC 13 : mp->pos = 0;
474 :
475 : /*
476 : * now process directly from data
6482 bruce 477 ECB : */
6482 bruce 478 CBC 20 : while (len > 0)
6482 bruce 479 ECB : {
6482 bruce 480 GIC 19 : if (len > mp->block_size)
481 : {
6482 bruce 482 CBC 7 : res = wrap_process(mp, data, mp->block_size);
6482 bruce 483 GIC 7 : if (res < 0)
6482 bruce 484 UIC 0 : return res;
6482 bruce 485 GIC 7 : data += mp->block_size;
6482 bruce 486 CBC 7 : len -= mp->block_size;
487 : }
488 : else
489 : {
490 12 : memcpy(mp->buf, data, len);
6482 bruce 491 GIC 12 : mp->pos += len;
6482 bruce 492 CBC 12 : break;
493 : }
6482 bruce 494 ECB : }
6482 bruce 495 CBC 13 : return 0;
6482 bruce 496 EUB : }
497 :
498 : int
5050 bruce 499 CBC 42 : pushf_flush(PushFilter *mp)
500 : {
6482 bruce 501 ECB : int res;
502 :
6482 bruce 503 GBC 241 : while (mp)
504 : {
6482 bruce 505 GIC 199 : if (mp->block_size > 0)
6482 bruce 506 ECB : {
6482 bruce 507 GIC 120 : res = wrap_process(mp, mp->buf, mp->pos);
6482 bruce 508 CBC 120 : if (res < 0)
6482 bruce 509 UIC 0 : return res;
510 : }
511 :
6482 bruce 512 GIC 199 : if (mp->op->flush)
513 : {
514 119 : res = mp->op->flush(mp->next, mp->priv);
515 119 : if (res < 0)
6482 bruce 516 LBC 0 : return res;
517 : }
6482 bruce 518 ECB :
6482 bruce 519 CBC 199 : mp = mp->next;
520 : }
521 42 : return 0;
6482 bruce 522 ECB : }
523 :
524 :
525 : /*
526 : * write to MBuf
527 : */
528 : static int
5050 bruce 529 GIC 196 : push_into_mbuf(PushFilter *next, void *arg, const uint8 *data, int len)
530 : {
6482 bruce 531 CBC 196 : int res = 0;
6482 bruce 532 GIC 196 : MBuf *mbuf = arg;
6482 bruce 533 ECB :
6482 bruce 534 GIC 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
5050 544 36 : pushf_create_mbuf_writer(PushFilter **res, MBuf *dst)
545 : {
6482 546 36 : return pushf_create(res, &mbuf_filter, dst, NULL);
547 : }
|