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 
39 struct MBuf
40 {
45  bool no_write;
46  bool own_data;
47 };
48 
49 int
51 {
52  return mbuf->data_end - mbuf->read_pos;
53 }
54 
55 int
57 {
58  return mbuf->data_end - mbuf->data;
59 }
60 
61 int
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 
73 static void
74 prepare_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 
93 int
94 mbuf_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 
110 MBuf *
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 
130 MBuf *
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 
148 int
149 mbuf_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 
161 int
162 mbuf_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 {
184  int buflen;
186  int pos;
187  void *priv;
188 };
189 
190 int
191 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  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 
228 void
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 */
245 int
246 pullf_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 
262 int
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  */
300 int
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);
312  return PXE_PGP_CORRUPT_DATA;
313  }
314  if (p != dst)
315  memcpy(dst, p, len);
316  return 0;
317 }
318 
319 /*
320  * read from MBuf
321  */
322 static int
323 pull_from_mbuf(void *arg, PullFilter *src, int len,
324  uint8 **data_p, uint8 *buf, int buflen)
325 {
326  MBuf *mbuf = arg;
327 
328  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
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 
356 int
357 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  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 
394 void
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 
410 void
412 {
413  PushFilter *tmp;
414 
415  while (mp)
416  {
417  tmp = mp->next;
418  pushf_free(mp);
419  mp = tmp;
420  }
421 }
422 
423 static 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 */
438 int
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 
498 int
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  */
528 static 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 
539 static const struct PushFilterOps mbuf_filter = {
540  NULL, push_into_mbuf, NULL, NULL
541 };
542 
543 int
545 {
546  return pushf_create(res, &mbuf_filter, dst, NULL);
547 }
static int32 next
Definition: blutils.c:219
unsigned char uint8
Definition: c.h:440
MBuf * mbuf_create_from_data(uint8 *data, int len)
Definition: mbuf.c:131
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
int mbuf_steal_data(MBuf *mbuf, uint8 **data_p)
Definition: mbuf.c:162
#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
MBuf * mbuf_create(int len)
Definition: mbuf.c:111
void pfree(void *pointer)
Definition: mcxt.c:1306
void * palloc0(Size size)
Definition: mcxt.c:1230
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1321
void * palloc(Size size)
Definition: mcxt.c:1199
void * arg
const void size_t len
const void * data
static char * buf
Definition: pg_test_fsync.c:67
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:160