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