LCOV - code coverage report
Current view: top level - contrib/pgcrypto - mbuf.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 205 219 93.6 %
Date: 2024-04-19 13:11:37 Functions: 24 24 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14