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