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  px_free(mbuf->data);
74  }
75  px_free(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 = px_realloc(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 = px_alloc(sizeof *mbuf);
125  mbuf->data = px_alloc(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 = px_alloc(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 = px_alloc(sizeof(*pf));
223  memset(pf, 0, sizeof(*pf));
224  pf->buflen = res;
225  pf->op = op;
226  pf->priv = priv;
227  pf->src = src;
228  if (pf->buflen > 0)
229  {
230  pf->buf = px_alloc(pf->buflen);
231  pf->pos = 0;
232  }
233  else
234  {
235  pf->buf = NULL;
236  pf->pos = 0;
237  }
238  *pf_p = pf;
239  return 0;
240 }
241 
242 void
244 {
245  if (pf->op->free)
246  pf->op->free(pf->priv);
247 
248  if (pf->buf)
249  {
250  px_memset(pf->buf, 0, pf->buflen);
251  px_free(pf->buf);
252  }
253 
254  px_memset(pf, 0, sizeof(*pf));
255  px_free(pf);
256 }
257 
258 /* may return less data than asked, 0 means eof */
259 int
260 pullf_read(PullFilter *pf, int len, uint8 **data_p)
261 {
262  int res;
263 
264  if (pf->op->pull)
265  {
266  if (pf->buflen && len > pf->buflen)
267  len = pf->buflen;
268  res = pf->op->pull(pf->priv, pf->src, len, data_p,
269  pf->buf, pf->buflen);
270  }
271  else
272  res = pullf_read(pf->src, len, data_p);
273  return res;
274 }
275 
276 int
277 pullf_read_max(PullFilter *pf, int len, uint8 **data_p, uint8 *tmpbuf)
278 {
279  int res,
280  total;
281  uint8 *tmp;
282 
283  res = pullf_read(pf, len, data_p);
284  if (res <= 0 || res == len)
285  return res;
286 
287  /* read was shorter, use tmpbuf */
288  memcpy(tmpbuf, *data_p, res);
289  *data_p = tmpbuf;
290  len -= res;
291  total = res;
292 
293  while (len > 0)
294  {
295  res = pullf_read(pf, len, &tmp);
296  if (res < 0)
297  {
298  /* so the caller must clear only on success */
299  px_memset(tmpbuf, 0, total);
300  return res;
301  }
302  if (res == 0)
303  break;
304  memcpy(tmpbuf + total, tmp, res);
305  total += res;
306  len -= res;
307  }
308  return total;
309 }
310 
311 /*
312  * caller wants exactly len bytes and don't bother with references
313  */
314 int
315 pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
316 {
317  int res;
318  uint8 *p;
319 
320  res = pullf_read_max(src, len, &p, dst);
321  if (res < 0)
322  return res;
323  if (res != len)
324  {
325  px_debug("pullf_read_fixed: need=%d got=%d", len, res);
326  return PXE_PGP_CORRUPT_DATA;
327  }
328  if (p != dst)
329  memcpy(dst, p, len);
330  return 0;
331 }
332 
333 /*
334  * read from MBuf
335  */
336 static int
337 pull_from_mbuf(void *arg, PullFilter *src, int len,
338  uint8 **data_p, uint8 *buf, int buflen)
339 {
340  MBuf *mbuf = arg;
341 
342  return mbuf_grab(mbuf, len, data_p);
343 }
344 
345 static const struct PullFilterOps mbuf_reader = {
346  NULL, pull_from_mbuf, NULL
347 };
348 
349 int
351 {
352  return pullf_create(mp_p, &mbuf_reader, src, NULL);
353 }
354 
355 
356 /*
357  * PushFilter
358  */
359 
361 {
366  int pos;
367  void *priv;
368 };
369 
370 int
371 pushf_create(PushFilter **mp_p, const PushFilterOps *op, void *init_arg, PushFilter *next)
372 {
373  PushFilter *mp;
374  void *priv;
375  int res;
376 
377  if (op->init != NULL)
378  {
379  res = op->init(next, init_arg, &priv);
380  if (res < 0)
381  return res;
382  }
383  else
384  {
385  priv = init_arg;
386  res = 0;
387  }
388 
389  mp = px_alloc(sizeof(*mp));
390  memset(mp, 0, sizeof(*mp));
391  mp->block_size = res;
392  mp->op = op;
393  mp->priv = priv;
394  mp->next = next;
395  if (mp->block_size > 0)
396  {
397  mp->buf = px_alloc(mp->block_size);
398  mp->pos = 0;
399  }
400  else
401  {
402  mp->buf = NULL;
403  mp->pos = 0;
404  }
405  *mp_p = mp;
406  return 0;
407 }
408 
409 void
411 {
412  if (mp->op->free)
413  mp->op->free(mp->priv);
414 
415  if (mp->buf)
416  {
417  px_memset(mp->buf, 0, mp->block_size);
418  px_free(mp->buf);
419  }
420 
421  px_memset(mp, 0, sizeof(*mp));
422  px_free(mp);
423 }
424 
425 void
427 {
428  PushFilter *tmp;
429 
430  while (mp)
431  {
432  tmp = mp->next;
433  pushf_free(mp);
434  mp = tmp;
435  }
436 }
437 
438 static int
439 wrap_process(PushFilter *mp, const uint8 *data, int len)
440 {
441  int res;
442 
443  if (mp->op->push != NULL)
444  res = mp->op->push(mp->next, mp->priv, data, len);
445  else
446  res = pushf_write(mp->next, data, len);
447  if (res > 0)
448  return PXE_BUG;
449  return res;
450 }
451 
452 /* consumes all data, returns len on success */
453 int
454 pushf_write(PushFilter *mp, const uint8 *data, int len)
455 {
456  int need,
457  res;
458 
459  /*
460  * no buffering
461  */
462  if (mp->block_size <= 0)
463  return wrap_process(mp, data, len);
464 
465  /*
466  * try to empty buffer
467  */
468  need = mp->block_size - mp->pos;
469  if (need > 0)
470  {
471  if (len < need)
472  {
473  memcpy(mp->buf + mp->pos, data, len);
474  mp->pos += len;
475  return 0;
476  }
477  memcpy(mp->buf + mp->pos, data, need);
478  len -= need;
479  data += need;
480  }
481 
482  /*
483  * buffer full, process
484  */
485  res = wrap_process(mp, mp->buf, mp->block_size);
486  if (res < 0)
487  return res;
488  mp->pos = 0;
489 
490  /*
491  * now process directly from data
492  */
493  while (len > 0)
494  {
495  if (len > mp->block_size)
496  {
497  res = wrap_process(mp, data, mp->block_size);
498  if (res < 0)
499  return res;
500  data += mp->block_size;
501  len -= mp->block_size;
502  }
503  else
504  {
505  memcpy(mp->buf, data, len);
506  mp->pos += len;
507  break;
508  }
509  }
510  return 0;
511 }
512 
513 int
515 {
516  int res;
517 
518  while (mp)
519  {
520  if (mp->block_size > 0)
521  {
522  res = wrap_process(mp, mp->buf, mp->pos);
523  if (res < 0)
524  return res;
525  }
526 
527  if (mp->op->flush)
528  {
529  res = mp->op->flush(mp->next, mp->priv);
530  if (res < 0)
531  return res;
532  }
533 
534  mp = mp->next;
535  }
536  return 0;
537 }
538 
539 
540 /*
541  * write to MBuf
542  */
543 static int
544 push_into_mbuf(PushFilter *next, void *arg, const uint8 *data, int len)
545 {
546  int res = 0;
547  MBuf *mbuf = arg;
548 
549  if (len > 0)
550  res = mbuf_append(mbuf, data, len);
551  return res < 0 ? res : 0;
552 }
553 
554 static const struct PushFilterOps mbuf_filter = {
555  NULL, push_into_mbuf, NULL, NULL
556 };
557 
558 int
560 {
561  return pushf_create(res, &mbuf_filter, dst, NULL);
562 }
#define STEP
Definition: mbuf.c:37
void pushf_free(PushFilter *mp)
Definition: mbuf.c:410
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:559
#define PXE_PGP_CORRUPT_DATA
Definition: px.h:78
static int32 next
Definition: blutils.c:218
int pullf_read(PullFilter *pf, int len, uint8 **data_p)
Definition: mbuf.c:260
void pullf_free(PullFilter *pf)
Definition: mbuf.c:243
const PushFilterOps * op
Definition: mbuf.c:363
int pushf_flush(PushFilter *mp)
Definition: mbuf.c:514
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:345
int pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
Definition: mbuf.c:315
#define px_free(p)
Definition: px.h:46
PullFilter * src
Definition: mbuf.c:195
unsigned char uint8
Definition: c.h:365
static int wrap_process(PushFilter *mp, const uint8 *data, int len)
Definition: mbuf.c:439
void * priv
Definition: mbuf.c:367
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:350
uint8 * buf_end
Definition: mbuf.c:44
int mbuf_tell(MBuf *mbuf)
Definition: mbuf.c:62
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:67
int pos
Definition: mbuf.c:366
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:554
#define PXE_BUG
Definition: px.h:70
void pushf_free_all(PushFilter *mp)
Definition: mbuf.c:426
#define px_realloc(p, s)
Definition: px.h:45
int mbuf_avail(MBuf *mbuf)
Definition: mbuf.c:50
int mbuf_append(MBuf *dst, const uint8 *buf, int len)
Definition: mbuf.c:100
static int pull_from_mbuf(void *arg, PullFilter *src, int len, uint8 **data_p, uint8 *buf, int buflen)
Definition: mbuf.c:337
int pushf_create(PushFilter **mp_p, const PushFilterOps *op, void *init_arg, PushFilter *next)
Definition: mbuf.c:371
uint8 * read_pos
Definition: mbuf.c:43
void(* free)(void *priv)
Definition: mbuf.h:73
PushFilter * next
Definition: mbuf.c:362
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:152
Definition: mbuf.c:39
int mbuf_rewind(MBuf *mbuf)
Definition: mbuf.c:168
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:155
#define px_alloc(s)
Definition: px.h:44
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
static int push_into_mbuf(PushFilter *next, void *arg, const uint8 *data, int len)
Definition: mbuf.c:544
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:454
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:126
int mbuf_steal_data(MBuf *mbuf, uint8 **data_p)
Definition: mbuf.c:175
uint8 * buf
Definition: mbuf.c:365
int pullf_read_max(PullFilter *pf, int len, uint8 **data_p, uint8 *tmpbuf)
Definition: mbuf.c:277
int block_size
Definition: mbuf.c:364