Header And Logo

PostgreSQL
| The world's most advanced open source database.

mbuf.c

Go to the documentation of this file.
00001 /*
00002  * mbuf.c
00003  *      Memory buffer operations.
00004  *
00005  * Copyright (c) 2005 Marko Kreen
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * contrib/pgcrypto/mbuf.c
00030  */
00031 
00032 #include "postgres.h"
00033 
00034 #include "px.h"
00035 #include "mbuf.h"
00036 
00037 #define STEP  (16*1024)
00038 
00039 struct MBuf
00040 {
00041     uint8      *data;
00042     uint8      *data_end;
00043     uint8      *read_pos;
00044     uint8      *buf_end;
00045     bool        no_write;
00046     bool        own_data;
00047 };
00048 
00049 int
00050 mbuf_avail(MBuf *mbuf)
00051 {
00052     return mbuf->data_end - mbuf->read_pos;
00053 }
00054 
00055 int
00056 mbuf_size(MBuf *mbuf)
00057 {
00058     return mbuf->data_end - mbuf->data;
00059 }
00060 
00061 int
00062 mbuf_tell(MBuf *mbuf)
00063 {
00064     return mbuf->read_pos - mbuf->data;
00065 }
00066 
00067 int
00068 mbuf_free(MBuf *mbuf)
00069 {
00070     if (mbuf->own_data)
00071     {
00072         memset(mbuf->data, 0, mbuf->buf_end - mbuf->data);
00073         px_free(mbuf->data);
00074     }
00075     px_free(mbuf);
00076     return 0;
00077 }
00078 
00079 static void
00080 prepare_room(MBuf *mbuf, int block_len)
00081 {
00082     uint8      *newbuf;
00083     unsigned    newlen;
00084 
00085     if (mbuf->data_end + block_len <= mbuf->buf_end)
00086         return;
00087 
00088     newlen = (mbuf->buf_end - mbuf->data)
00089         + ((block_len + STEP + STEP - 1) & -STEP);
00090 
00091     newbuf = px_realloc(mbuf->data, newlen);
00092 
00093     mbuf->buf_end = newbuf + newlen;
00094     mbuf->data_end = newbuf + (mbuf->data_end - mbuf->data);
00095     mbuf->read_pos = newbuf + (mbuf->read_pos - mbuf->data);
00096     mbuf->data = newbuf;
00097 
00098     return;
00099 }
00100 
00101 int
00102 mbuf_append(MBuf *dst, const uint8 *buf, int len)
00103 {
00104     if (dst->no_write)
00105     {
00106         px_debug("mbuf_append: no_write");
00107         return PXE_BUG;
00108     }
00109 
00110     prepare_room(dst, len);
00111 
00112     memcpy(dst->data_end, buf, len);
00113     dst->data_end += len;
00114 
00115     return 0;
00116 }
00117 
00118 MBuf *
00119 mbuf_create(int len)
00120 {
00121     MBuf       *mbuf;
00122 
00123     if (!len)
00124         len = 8192;
00125 
00126     mbuf = px_alloc(sizeof *mbuf);
00127     mbuf->data = px_alloc(len);
00128     mbuf->buf_end = mbuf->data + len;
00129     mbuf->data_end = mbuf->data;
00130     mbuf->read_pos = mbuf->data;
00131 
00132     mbuf->no_write = false;
00133     mbuf->own_data = true;
00134 
00135     return mbuf;
00136 }
00137 
00138 MBuf *
00139 mbuf_create_from_data(uint8 *data, int len)
00140 {
00141     MBuf       *mbuf;
00142 
00143     mbuf = px_alloc(sizeof *mbuf);
00144     mbuf->data = (uint8 *) data;
00145     mbuf->buf_end = mbuf->data + len;
00146     mbuf->data_end = mbuf->data + len;
00147     mbuf->read_pos = mbuf->data;
00148 
00149     mbuf->no_write = true;
00150     mbuf->own_data = false;
00151 
00152     return mbuf;
00153 }
00154 
00155 
00156 int
00157 mbuf_grab(MBuf *mbuf, int len, uint8 **data_p)
00158 {
00159     if (len > mbuf_avail(mbuf))
00160         len = mbuf_avail(mbuf);
00161 
00162     mbuf->no_write = true;
00163 
00164     *data_p = mbuf->read_pos;
00165     mbuf->read_pos += len;
00166     return len;
00167 }
00168 
00169 int
00170 mbuf_rewind(MBuf *mbuf)
00171 {
00172     mbuf->read_pos = mbuf->data;
00173     return 0;
00174 }
00175 
00176 int
00177 mbuf_steal_data(MBuf *mbuf, uint8 **data_p)
00178 {
00179     int         len = mbuf_size(mbuf);
00180 
00181     mbuf->no_write = true;
00182     mbuf->own_data = false;
00183 
00184     *data_p = mbuf->data;
00185 
00186     mbuf->data = mbuf->data_end = mbuf->read_pos = mbuf->buf_end = NULL;
00187 
00188     return len;
00189 }
00190 
00191 /*
00192  * PullFilter
00193  */
00194 
00195 struct PullFilter
00196 {
00197     PullFilter *src;
00198     const PullFilterOps *op;
00199     int         buflen;
00200     uint8      *buf;
00201     int         pos;
00202     void       *priv;
00203 };
00204 
00205 int
00206 pullf_create(PullFilter **pf_p, const PullFilterOps *op, void *init_arg, PullFilter *src)
00207 {
00208     PullFilter *pf;
00209     void       *priv;
00210     int         res;
00211 
00212     if (op->init != NULL)
00213     {
00214         res = op->init(&priv, init_arg, src);
00215         if (res < 0)
00216             return res;
00217     }
00218     else
00219     {
00220         priv = init_arg;
00221         res = 0;
00222     }
00223 
00224     pf = px_alloc(sizeof(*pf));
00225     memset(pf, 0, sizeof(*pf));
00226     pf->buflen = res;
00227     pf->op = op;
00228     pf->priv = priv;
00229     pf->src = src;
00230     if (pf->buflen > 0)
00231     {
00232         pf->buf = px_alloc(pf->buflen);
00233         pf->pos = 0;
00234     }
00235     else
00236     {
00237         pf->buf = NULL;
00238         pf->pos = 0;
00239     }
00240     *pf_p = pf;
00241     return 0;
00242 }
00243 
00244 void
00245 pullf_free(PullFilter *pf)
00246 {
00247     if (pf->op->free)
00248         pf->op->free(pf->priv);
00249 
00250     if (pf->buf)
00251     {
00252         memset(pf->buf, 0, pf->buflen);
00253         px_free(pf->buf);
00254     }
00255 
00256     memset(pf, 0, sizeof(*pf));
00257     px_free(pf);
00258 }
00259 
00260 /* may return less data than asked, 0 means eof */
00261 int
00262 pullf_read(PullFilter *pf, int len, uint8 **data_p)
00263 {
00264     int         res;
00265 
00266     if (pf->op->pull)
00267     {
00268         if (pf->buflen && len > pf->buflen)
00269             len = pf->buflen;
00270         res = pf->op->pull(pf->priv, pf->src, len, data_p,
00271                            pf->buf, pf->buflen);
00272     }
00273     else
00274         res = pullf_read(pf->src, len, data_p);
00275     return res;
00276 }
00277 
00278 int
00279 pullf_read_max(PullFilter *pf, int len, uint8 **data_p, uint8 *tmpbuf)
00280 {
00281     int         res,
00282                 total;
00283     uint8      *tmp;
00284 
00285     res = pullf_read(pf, len, data_p);
00286     if (res <= 0 || res == len)
00287         return res;
00288 
00289     /* read was shorter, use tmpbuf */
00290     memcpy(tmpbuf, *data_p, res);
00291     *data_p = tmpbuf;
00292     len -= res;
00293     total = res;
00294 
00295     while (len > 0)
00296     {
00297         res = pullf_read(pf, len, &tmp);
00298         if (res < 0)
00299         {
00300             /* so the caller must clear only on success */
00301             memset(tmpbuf, 0, total);
00302             return res;
00303         }
00304         if (res == 0)
00305             break;
00306         memcpy(tmpbuf + total, tmp, res);
00307         total += res;
00308     }
00309     return total;
00310 }
00311 
00312 /*
00313  * caller wants exatly len bytes and dont bother with references
00314  */
00315 int
00316 pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
00317 {
00318     int         res;
00319     uint8      *p;
00320 
00321     res = pullf_read_max(src, len, &p, dst);
00322     if (res < 0)
00323         return res;
00324     if (res != len)
00325     {
00326         px_debug("pullf_read_fixed: need=%d got=%d", len, res);
00327         return PXE_MBUF_SHORT_READ;
00328     }
00329     if (p != dst)
00330         memcpy(dst, p, len);
00331     return 0;
00332 }
00333 
00334 /*
00335  * read from MBuf
00336  */
00337 static int
00338 pull_from_mbuf(void *arg, PullFilter *src, int len,
00339                uint8 **data_p, uint8 *buf, int buflen)
00340 {
00341     MBuf       *mbuf = arg;
00342 
00343     return mbuf_grab(mbuf, len, data_p);
00344 }
00345 
00346 static const struct PullFilterOps mbuf_reader = {
00347     NULL, pull_from_mbuf, NULL
00348 };
00349 
00350 int
00351 pullf_create_mbuf_reader(PullFilter **mp_p, MBuf *src)
00352 {
00353     return pullf_create(mp_p, &mbuf_reader, src, NULL);
00354 }
00355 
00356 
00357 /*
00358  * PushFilter
00359  */
00360 
00361 struct PushFilter
00362 {
00363     PushFilter *next;
00364     const PushFilterOps *op;
00365     int         block_size;
00366     uint8      *buf;
00367     int         pos;
00368     void       *priv;
00369 };
00370 
00371 int
00372 pushf_create(PushFilter **mp_p, const PushFilterOps *op, void *init_arg, PushFilter *next)
00373 {
00374     PushFilter *mp;
00375     void       *priv;
00376     int         res;
00377 
00378     if (op->init != NULL)
00379     {
00380         res = op->init(next, init_arg, &priv);
00381         if (res < 0)
00382             return res;
00383     }
00384     else
00385     {
00386         priv = init_arg;
00387         res = 0;
00388     }
00389 
00390     mp = px_alloc(sizeof(*mp));
00391     memset(mp, 0, sizeof(*mp));
00392     mp->block_size = res;
00393     mp->op = op;
00394     mp->priv = priv;
00395     mp->next = next;
00396     if (mp->block_size > 0)
00397     {
00398         mp->buf = px_alloc(mp->block_size);
00399         mp->pos = 0;
00400     }
00401     else
00402     {
00403         mp->buf = NULL;
00404         mp->pos = 0;
00405     }
00406     *mp_p = mp;
00407     return 0;
00408 }
00409 
00410 void
00411 pushf_free(PushFilter *mp)
00412 {
00413     if (mp->op->free)
00414         mp->op->free(mp->priv);
00415 
00416     if (mp->buf)
00417     {
00418         memset(mp->buf, 0, mp->block_size);
00419         px_free(mp->buf);
00420     }
00421 
00422     memset(mp, 0, sizeof(*mp));
00423     px_free(mp);
00424 }
00425 
00426 void
00427 pushf_free_all(PushFilter *mp)
00428 {
00429     PushFilter *tmp;
00430 
00431     while (mp)
00432     {
00433         tmp = mp->next;
00434         pushf_free(mp);
00435         mp = tmp;
00436     }
00437 }
00438 
00439 static int
00440 wrap_process(PushFilter *mp, const uint8 *data, int len)
00441 {
00442     int         res;
00443 
00444     if (mp->op->push != NULL)
00445         res = mp->op->push(mp->next, mp->priv, data, len);
00446     else
00447         res = pushf_write(mp->next, data, len);
00448     if (res > 0)
00449         return PXE_BUG;
00450     return res;
00451 }
00452 
00453 /* consumes all data, returns len on success */
00454 int
00455 pushf_write(PushFilter *mp, const uint8 *data, int len)
00456 {
00457     int         need,
00458                 res;
00459 
00460     /*
00461      * no buffering
00462      */
00463     if (mp->block_size <= 0)
00464         return wrap_process(mp, data, len);
00465 
00466     /*
00467      * try to empty buffer
00468      */
00469     need = mp->block_size - mp->pos;
00470     if (need > 0)
00471     {
00472         if (len < need)
00473         {
00474             memcpy(mp->buf + mp->pos, data, len);
00475             mp->pos += len;
00476             return 0;
00477         }
00478         memcpy(mp->buf + mp->pos, data, need);
00479         len -= need;
00480         data += need;
00481     }
00482 
00483     /*
00484      * buffer full, process
00485      */
00486     res = wrap_process(mp, mp->buf, mp->block_size);
00487     if (res < 0)
00488         return res;
00489     mp->pos = 0;
00490 
00491     /*
00492      * now process directly from data
00493      */
00494     while (len > 0)
00495     {
00496         if (len > mp->block_size)
00497         {
00498             res = wrap_process(mp, data, mp->block_size);
00499             if (res < 0)
00500                 return res;
00501             data += mp->block_size;
00502             len -= mp->block_size;
00503         }
00504         else
00505         {
00506             memcpy(mp->buf, data, len);
00507             mp->pos += len;
00508             break;
00509         }
00510     }
00511     return 0;
00512 }
00513 
00514 int
00515 pushf_flush(PushFilter *mp)
00516 {
00517     int         res;
00518 
00519     while (mp)
00520     {
00521         if (mp->block_size > 0)
00522         {
00523             res = wrap_process(mp, mp->buf, mp->pos);
00524             if (res < 0)
00525                 return res;
00526         }
00527 
00528         if (mp->op->flush)
00529         {
00530             res = mp->op->flush(mp->next, mp->priv);
00531             if (res < 0)
00532                 return res;
00533         }
00534 
00535         mp = mp->next;
00536     }
00537     return 0;
00538 }
00539 
00540 
00541 /*
00542  * write to MBuf
00543  */
00544 static int
00545 push_into_mbuf(PushFilter *next, void *arg, const uint8 *data, int len)
00546 {
00547     int         res = 0;
00548     MBuf       *mbuf = arg;
00549 
00550     if (len > 0)
00551         res = mbuf_append(mbuf, data, len);
00552     return res < 0 ? res : 0;
00553 }
00554 
00555 static const struct PushFilterOps mbuf_filter = {
00556     NULL, push_into_mbuf, NULL, NULL
00557 };
00558 
00559 int
00560 pushf_create_mbuf_writer(PushFilter **res, MBuf *dst)
00561 {
00562     return pushf_create(res, &mbuf_filter, dst, NULL);
00563 }