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