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