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