Fix UNLISTEN to fall out quickly if the current backend has never executed
[PostgreSQL.git] / contrib / pgcrypto / mbuf.c
blob2be7c1fd0f3c91dec5522e52b32a14cbc45a3546
1 /*
2 * mbuf.c
3 * Memory buffer operations.
5 * Copyright (c) 2005 Marko Kreen
6 * All rights reserved.
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.
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.
29 * $PostgreSQL$
32 #include "postgres.h"
34 #include "px.h"
35 #include "mbuf.h"
37 #define STEP (16*1024)
39 struct MBuf
41 uint8 *data;
42 uint8 *data_end;
43 uint8 *read_pos;
44 uint8 *buf_end;
45 bool no_write;
46 bool own_data;
49 int
50 mbuf_avail(MBuf * mbuf)
52 return mbuf->data_end - mbuf->read_pos;
55 int
56 mbuf_size(MBuf * mbuf)
58 return mbuf->data_end - mbuf->data;
61 int
62 mbuf_tell(MBuf * mbuf)
64 return mbuf->read_pos - mbuf->data;
67 int
68 mbuf_free(MBuf * mbuf)
70 if (mbuf->own_data)
72 memset(mbuf->data, 0, mbuf->buf_end - mbuf->data);
73 px_free(mbuf->data);
75 px_free(mbuf);
76 return 0;
79 static void
80 prepare_room(MBuf * mbuf, int block_len)
82 uint8 *newbuf;
83 unsigned newlen;
85 if (mbuf->data_end + block_len <= mbuf->buf_end)
86 return;
88 newlen = (mbuf->buf_end - mbuf->data)
89 + ((block_len + STEP + STEP - 1) & -STEP);
91 newbuf = px_realloc(mbuf->data, newlen);
93 mbuf->buf_end = newbuf + newlen;
94 mbuf->data_end = newbuf + (mbuf->data_end - mbuf->data);
95 mbuf->read_pos = newbuf + (mbuf->read_pos - mbuf->data);
96 mbuf->data = newbuf;
98 return;
102 mbuf_append(MBuf * dst, const uint8 *buf, int len)
104 if (dst->no_write)
106 px_debug("mbuf_append: no_write");
107 return PXE_BUG;
110 prepare_room(dst, len);
112 memcpy(dst->data_end, buf, len);
113 dst->data_end += len;
115 return 0;
118 MBuf *
119 mbuf_create(int len)
121 MBuf *mbuf;
123 if (!len)
124 len = 8192;
126 mbuf = px_alloc(sizeof *mbuf);
127 mbuf->data = px_alloc(len);
128 mbuf->buf_end = mbuf->data + len;
129 mbuf->data_end = mbuf->data;
130 mbuf->read_pos = mbuf->data;
132 mbuf->no_write = false;
133 mbuf->own_data = true;
135 return mbuf;
138 MBuf *
139 mbuf_create_from_data(const uint8 *data, int len)
141 MBuf *mbuf;
143 mbuf = px_alloc(sizeof *mbuf);
144 mbuf->data = (uint8 *) data;
145 mbuf->buf_end = mbuf->data + len;
146 mbuf->data_end = mbuf->data + len;
147 mbuf->read_pos = mbuf->data;
149 mbuf->no_write = true;
150 mbuf->own_data = false;
152 return mbuf;
157 mbuf_grab(MBuf * mbuf, int len, uint8 **data_p)
159 if (len > mbuf_avail(mbuf))
160 len = mbuf_avail(mbuf);
162 mbuf->no_write = true;
164 *data_p = mbuf->read_pos;
165 mbuf->read_pos += len;
166 return len;
170 mbuf_rewind(MBuf * mbuf)
172 mbuf->read_pos = mbuf->data;
173 return 0;
177 mbuf_steal_data(MBuf * mbuf, uint8 **data_p)
179 int len = mbuf_size(mbuf);
181 mbuf->no_write = true;
182 mbuf->own_data = false;
184 *data_p = mbuf->data;
186 mbuf->data = mbuf->data_end = mbuf->read_pos = mbuf->buf_end = NULL;
188 return len;
192 * PullFilter
195 struct PullFilter
197 PullFilter *src;
198 const PullFilterOps *op;
199 int buflen;
200 uint8 *buf;
201 int pos;
202 void *priv;
206 pullf_create(PullFilter ** pf_p, const PullFilterOps * op, void *init_arg, PullFilter * src)
208 PullFilter *pf;
209 void *priv;
210 int res;
212 if (op->init != NULL)
214 res = op->init(&priv, init_arg, src);
215 if (res < 0)
216 return res;
218 else
220 priv = init_arg;
221 res = 0;
224 pf = px_alloc(sizeof(*pf));
225 memset(pf, 0, sizeof(*pf));
226 pf->buflen = res;
227 pf->op = op;
228 pf->priv = priv;
229 pf->src = src;
230 if (pf->buflen > 0)
232 pf->buf = px_alloc(pf->buflen);
233 pf->pos = 0;
235 else
237 pf->buf = NULL;
238 pf->pos = 0;
240 *pf_p = pf;
241 return 0;
244 void
245 pullf_free(PullFilter * pf)
247 if (pf->op->free)
248 pf->op->free(pf->priv);
250 if (pf->buf)
252 memset(pf->buf, 0, pf->buflen);
253 px_free(pf->buf);
256 memset(pf, 0, sizeof(*pf));
257 px_free(pf);
260 /* may return less data than asked, 0 means eof */
262 pullf_read(PullFilter * pf, int len, uint8 **data_p)
264 int res;
266 if (pf->op->pull)
268 if (pf->buflen && len > pf->buflen)
269 len = pf->buflen;
270 res = pf->op->pull(pf->priv, pf->src, len, data_p,
271 pf->buf, pf->buflen);
273 else
274 res = pullf_read(pf->src, len, data_p);
275 return res;
279 pullf_read_max(PullFilter * pf, int len, uint8 **data_p, uint8 *tmpbuf)
281 int res,
282 total;
283 uint8 *tmp;
285 res = pullf_read(pf, len, data_p);
286 if (res <= 0 || res == len)
287 return res;
289 /* read was shorter, use tmpbuf */
290 memcpy(tmpbuf, *data_p, res);
291 *data_p = tmpbuf;
292 len -= res;
293 total = res;
295 while (len > 0)
297 res = pullf_read(pf, len, &tmp);
298 if (res < 0)
300 /* so the caller must clear only on success */
301 memset(tmpbuf, 0, total);
302 return res;
304 if (res == 0)
305 break;
306 memcpy(tmpbuf + total, tmp, res);
307 total += res;
309 return total;
313 * caller wants exatly len bytes and dont bother with references
316 pullf_read_fixed(PullFilter * src, int len, uint8 *dst)
318 int res;
319 uint8 *p;
321 res = pullf_read_max(src, len, &p, dst);
322 if (res < 0)
323 return res;
324 if (res != len)
326 px_debug("pullf_read_fixed: need=%d got=%d", len, res);
327 return PXE_MBUF_SHORT_READ;
329 if (p != dst)
330 memcpy(dst, p, len);
331 return 0;
335 * read from MBuf
337 static int
338 pull_from_mbuf(void *arg, PullFilter * src, int len,
339 uint8 **data_p, uint8 *buf, int buflen)
341 MBuf *mbuf = arg;
343 return mbuf_grab(mbuf, len, data_p);
346 static const struct PullFilterOps mbuf_reader = {
347 NULL, pull_from_mbuf, NULL
351 pullf_create_mbuf_reader(PullFilter ** mp_p, MBuf * src)
353 return pullf_create(mp_p, &mbuf_reader, src, NULL);
358 * PushFilter
361 struct PushFilter
363 PushFilter *next;
364 const PushFilterOps *op;
365 int block_size;
366 uint8 *buf;
367 int pos;
368 void *priv;
372 pushf_create(PushFilter ** mp_p, const PushFilterOps * op, void *init_arg, PushFilter * next)
374 PushFilter *mp;
375 void *priv;
376 int res;
378 if (op->init != NULL)
380 res = op->init(next, init_arg, &priv);
381 if (res < 0)
382 return res;
384 else
386 priv = init_arg;
387 res = 0;
390 mp = px_alloc(sizeof(*mp));
391 memset(mp, 0, sizeof(*mp));
392 mp->block_size = res;
393 mp->op = op;
394 mp->priv = priv;
395 mp->next = next;
396 if (mp->block_size > 0)
398 mp->buf = px_alloc(mp->block_size);
399 mp->pos = 0;
401 else
403 mp->buf = NULL;
404 mp->pos = 0;
406 *mp_p = mp;
407 return 0;
410 void
411 pushf_free(PushFilter * mp)
413 if (mp->op->free)
414 mp->op->free(mp->priv);
416 if (mp->buf)
418 memset(mp->buf, 0, mp->block_size);
419 px_free(mp->buf);
422 memset(mp, 0, sizeof(*mp));
423 px_free(mp);
426 void
427 pushf_free_all(PushFilter * mp)
429 PushFilter *tmp;
431 while (mp)
433 tmp = mp->next;
434 pushf_free(mp);
435 mp = tmp;
439 static int
440 wrap_process(PushFilter * mp, const uint8 *data, int len)
442 int res;
444 if (mp->op->push != NULL)
445 res = mp->op->push(mp->next, mp->priv, data, len);
446 else
447 res = pushf_write(mp->next, data, len);
448 if (res > 0)
449 return PXE_BUG;
450 return res;
453 /* consumes all data, returns len on success */
455 pushf_write(PushFilter * mp, const uint8 *data, int len)
457 int need,
458 res;
461 * no buffering
463 if (mp->block_size <= 0)
464 return wrap_process(mp, data, len);
467 * try to empty buffer
469 need = mp->block_size - mp->pos;
470 if (need > 0)
472 if (len < need)
474 memcpy(mp->buf + mp->pos, data, len);
475 mp->pos += len;
476 return 0;
478 memcpy(mp->buf + mp->pos, data, need);
479 len -= need;
480 data += need;
484 * buffer full, process
486 res = wrap_process(mp, mp->buf, mp->block_size);
487 if (res < 0)
488 return res;
489 mp->pos = 0;
492 * now process directly from data
494 while (len > 0)
496 if (len > mp->block_size)
498 res = wrap_process(mp, data, mp->block_size);
499 if (res < 0)
500 return res;
501 data += mp->block_size;
502 len -= mp->block_size;
504 else
506 memcpy(mp->buf, data, len);
507 mp->pos += len;
508 break;
511 return 0;
515 pushf_flush(PushFilter * mp)
517 int res;
519 while (mp)
521 if (mp->block_size > 0)
523 res = wrap_process(mp, mp->buf, mp->pos);
524 if (res < 0)
525 return res;
528 if (mp->op->flush)
530 res = mp->op->flush(mp->next, mp->priv);
531 if (res < 0)
532 return res;
535 mp = mp->next;
537 return 0;
542 * write to MBuf
544 static int
545 push_into_mbuf(PushFilter * next, void *arg, const uint8 *data, int len)
547 int res = 0;
548 MBuf *mbuf = arg;
550 if (len > 0)
551 res = mbuf_append(mbuf, data, len);
552 return res < 0 ? res : 0;
555 static const struct PushFilterOps mbuf_filter = {
556 NULL, push_into_mbuf, NULL, NULL
560 pushf_create_mbuf_writer(PushFilter ** res, MBuf * dst)
562 return pushf_create(res, &mbuf_filter, dst, NULL);