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