LCOV - code coverage report
Current view: top level - lib/dpkg - buffer.c (source / functions) Hit Total Coverage
Test: dpkg 1.21.11 C code coverage Lines: 116 141 82.3 %
Date: 2022-12-03 00:40:01 Functions: 13 13 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 36 55 65.5 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * libdpkg - Debian packaging suite library routines
       3                 :            :  * buffer.c - buffer I/O handling routines
       4                 :            :  *
       5                 :            :  * Copyright © 1999, 2000 Wichert Akkerman <wakkerma@debian.org>
       6                 :            :  * Copyright © 2000-2003 Adam Heath <doogie@debian.org>
       7                 :            :  * Copyright © 2008-2012 Guillem Jover <guillem@debian.org>
       8                 :            :  *
       9                 :            :  * This is free software; you can redistribute it and/or modify
      10                 :            :  * it under the terms of the GNU General Public License as published by
      11                 :            :  * the Free Software Foundation; either version 2 of the License, or
      12                 :            :  * (at your option) any later version.
      13                 :            :  *
      14                 :            :  * This is distributed in the hope that it will be useful,
      15                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17                 :            :  * GNU General Public License for more details.
      18                 :            :  *
      19                 :            :  * You should have received a copy of the GNU General Public License
      20                 :            :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21                 :            :  */
      22                 :            : 
      23                 :            : #include <config.h>
      24                 :            : #include <compat.h>
      25                 :            : 
      26                 :            : #include <sys/types.h>
      27                 :            : 
      28                 :            : #include <errno.h>
      29                 :            : #include <md5.h>
      30                 :            : #include <string.h>
      31                 :            : #include <unistd.h>
      32                 :            : #include <stdlib.h>
      33                 :            : 
      34                 :            : #include <dpkg/i18n.h>
      35                 :            : #include <dpkg/dpkg.h>
      36                 :            : #include <dpkg/varbuf.h>
      37                 :            : #include <dpkg/fdio.h>
      38                 :            : #include <dpkg/buffer.h>
      39                 :            : 
      40                 :            : struct buffer_md5_ctx {
      41                 :            :         MD5_CTX ctx;
      42                 :            :         char *hash;
      43                 :            : };
      44                 :            : 
      45                 :            : static void
      46                 :          5 : buffer_md5_init(struct buffer_data *data)
      47                 :            : {
      48                 :            :         struct buffer_md5_ctx *ctx;
      49                 :            : 
      50                 :          5 :         ctx = m_malloc(sizeof(*ctx));
      51                 :          5 :         ctx->hash = data->arg.ptr;
      52                 :          5 :         data->arg.ptr = ctx;
      53                 :          5 :         MD5Init(&ctx->ctx);
      54                 :          5 : }
      55                 :            : 
      56                 :            : static off_t
      57                 :         82 : buffer_digest_init(struct buffer_data *data)
      58                 :            : {
      59      [ +  +  - ]:         82 :         switch (data->type) {
      60                 :         77 :         case BUFFER_DIGEST_NULL:
      61                 :         77 :                 break;
      62                 :          5 :         case BUFFER_DIGEST_MD5:
      63                 :          5 :                 buffer_md5_init(data);
      64                 :          5 :                 break;
      65                 :            :         }
      66                 :         82 :         return 0;
      67                 :            : }
      68                 :            : 
      69                 :            : static off_t
      70                 :        391 : buffer_digest_update(struct buffer_data *digest, const void *buf, off_t length)
      71                 :            : {
      72                 :        391 :         off_t ret = length;
      73                 :            : 
      74      [ +  +  - ]:        391 :         switch (digest->type) {
      75                 :        323 :         case BUFFER_DIGEST_NULL:
      76                 :        323 :                 break;
      77                 :         68 :         case BUFFER_DIGEST_MD5:
      78                 :         68 :                 MD5Update(&(((struct buffer_md5_ctx *)digest->arg.ptr)->ctx),
      79                 :            :                           buf, length);
      80                 :         68 :                 break;
      81                 :          0 :         default:
      82                 :          0 :                 internerr("unknown data type %i", digest->type);
      83                 :            :         }
      84                 :            : 
      85                 :        391 :         return ret;
      86                 :            : }
      87                 :            : 
      88                 :            : static void
      89                 :          5 : buffer_md5_done(struct buffer_data *data)
      90                 :            : {
      91                 :            :         struct buffer_md5_ctx *ctx;
      92                 :          5 :         unsigned char digest[16], *p = digest;
      93                 :            :         char *hash;
      94                 :            :         int i;
      95                 :            : 
      96                 :          5 :         ctx = (struct buffer_md5_ctx *)data->arg.ptr;
      97                 :          5 :         hash = ctx->hash;
      98                 :          5 :         MD5Final(digest, &ctx->ctx);
      99         [ +  + ]:         85 :         for (i = 0; i < 16; ++i) {
     100                 :         80 :                 sprintf(hash, "%02x", *p++);
     101                 :         80 :                 hash += 2;
     102                 :            :         }
     103                 :          5 :         *hash = '\0';
     104                 :          5 :         free(ctx);
     105                 :          5 : }
     106                 :            : 
     107                 :            : static off_t
     108                 :         82 : buffer_digest_done(struct buffer_data *data)
     109                 :            : {
     110      [ +  +  - ]:         82 :         switch (data->type) {
     111                 :         77 :         case BUFFER_DIGEST_NULL:
     112                 :         77 :                 break;
     113                 :          5 :         case BUFFER_DIGEST_MD5:
     114                 :          5 :                 buffer_md5_done(data);
     115                 :          5 :                 break;
     116                 :            :         }
     117                 :         82 :         return 0;
     118                 :            : }
     119                 :            : 
     120                 :            : static off_t
     121                 :        389 : buffer_write(struct buffer_data *data, const void *buf, off_t length,
     122                 :            :              struct dpkg_error *err)
     123                 :            : {
     124                 :        389 :         off_t ret = length;
     125                 :            : 
     126   [ +  +  +  - ]:        389 :         switch (data->type) {
     127                 :          1 :         case BUFFER_WRITE_VBUF:
     128                 :          1 :                 varbuf_add_buf((struct varbuf *)data->arg.ptr, buf, length);
     129                 :          1 :                 break;
     130                 :        322 :         case BUFFER_WRITE_FD:
     131                 :        322 :                 ret = fd_write(data->arg.i, buf, length);
     132         [ -  + ]:        322 :                 if (ret < 0)
     133                 :          0 :                         dpkg_put_errno(err, _("failed to write"));
     134                 :        322 :                 break;
     135                 :         66 :         case BUFFER_WRITE_NULL:
     136                 :         66 :                 break;
     137                 :          0 :         default:
     138                 :          0 :                 internerr("unknown data type %i", data->type);
     139                 :            :         }
     140                 :            : 
     141                 :        389 :         return ret;
     142                 :            : }
     143                 :            : 
     144                 :            : static off_t
     145                 :        406 : buffer_read(struct buffer_data *data, void *buf, off_t length,
     146                 :            :             struct dpkg_error *err)
     147                 :            : {
     148                 :            :         off_t ret;
     149                 :            : 
     150         [ +  - ]:        406 :         switch (data->type) {
     151                 :        406 :         case BUFFER_READ_FD:
     152                 :        406 :                 ret = fd_read(data->arg.i, buf, length);
     153         [ -  + ]:        406 :                 if (ret < 0)
     154                 :          0 :                         dpkg_put_errno(err, _("failed to read"));
     155                 :        406 :                 break;
     156                 :          0 :         default:
     157                 :          0 :                 internerr("unknown data type %i", data->type);
     158                 :            :         }
     159                 :            : 
     160                 :        406 :         return ret;
     161                 :            : }
     162                 :            : 
     163                 :            : off_t
     164                 :          2 : buffer_digest(const void *input, void *output, int type, off_t limit)
     165                 :            : {
     166                 :          2 :         struct buffer_data data = { .arg.ptr = output, .type = type };
     167                 :            :         off_t ret;
     168                 :            : 
     169                 :          2 :         buffer_digest_init(&data);
     170                 :          2 :         ret = buffer_digest_update(&data, input, limit);
     171                 :          2 :         buffer_digest_done(&data);
     172                 :            : 
     173                 :          2 :         return ret;
     174                 :            : }
     175                 :            : 
     176                 :            : static off_t
     177                 :         80 : buffer_copy(struct buffer_data *read_data,
     178                 :            :             struct buffer_data *digest,
     179                 :            :             struct buffer_data *write_data,
     180                 :            :             off_t limit, struct dpkg_error *err)
     181                 :            : {
     182                 :            :         char *buf;
     183                 :         80 :         int bufsize = DPKG_BUFFER_SIZE;
     184                 :         80 :         off_t bytesread = 0, byteswritten = 0;
     185                 :         80 :         off_t totalread = 0, totalwritten = 0;
     186                 :            : 
     187   [ +  +  +  + ]:         80 :         if ((limit != -1) && (limit < bufsize))
     188                 :         42 :                 bufsize = limit;
     189         [ -  + ]:         80 :         if (bufsize == 0)
     190                 :          0 :                 buf = NULL;
     191                 :            :         else
     192                 :         80 :                 buf = m_malloc(bufsize);
     193                 :            : 
     194                 :         80 :         buffer_digest_init(digest);
     195                 :            : 
     196         [ +  + ]:        469 :         while (bufsize > 0) {
     197                 :        406 :                 bytesread = buffer_read(read_data, buf, bufsize, err);
     198         [ -  + ]:        406 :                 if (bytesread < 0)
     199                 :          0 :                         break;
     200         [ +  + ]:        406 :                 if (bytesread == 0)
     201                 :         17 :                         break;
     202                 :            : 
     203                 :        389 :                 totalread += bytesread;
     204                 :            : 
     205         [ +  + ]:        389 :                 if (limit != -1) {
     206                 :        245 :                         limit -= bytesread;
     207         [ +  + ]:        245 :                         if (limit < bufsize)
     208                 :         84 :                                 bufsize = limit;
     209                 :            :                 }
     210                 :            : 
     211                 :        389 :                 buffer_digest_update(digest, buf, bytesread);
     212                 :            : 
     213                 :        389 :                 byteswritten = buffer_write(write_data, buf, bytesread, err);
     214         [ -  + ]:        389 :                 if (byteswritten < 0)
     215                 :          0 :                         break;
     216         [ -  + ]:        389 :                 if (byteswritten == 0)
     217                 :          0 :                         break;
     218                 :            : 
     219                 :        389 :                 totalwritten += byteswritten;
     220                 :            :         }
     221                 :            : 
     222                 :         80 :         buffer_digest_done(digest);
     223                 :            : 
     224                 :         80 :         free(buf);
     225                 :            : 
     226   [ +  -  -  + ]:         80 :         if (bytesread < 0 || byteswritten < 0)
     227                 :          0 :                 return -1;
     228         [ -  + ]:         80 :         if (totalread != totalwritten)
     229                 :          0 :                 return -1;
     230         [ -  + ]:         80 :         if (limit > 0)
     231                 :          0 :                 return dpkg_put_error(err, _("unexpected end of file or stream"));
     232                 :            : 
     233                 :         80 :         return totalread;
     234                 :            : }
     235                 :            : 
     236                 :            : off_t
     237                 :         76 : buffer_copy_IntInt(int Iin, int Tin,
     238                 :            :                    void *Pdigest, int Tdigest,
     239                 :            :                    int Iout, int Tout,
     240                 :            :                    off_t limit, struct dpkg_error *err)
     241                 :            : {
     242                 :         76 :         struct buffer_data read_data = { .type = Tin, .arg.i = Iin };
     243                 :         76 :         struct buffer_data digest = { .type = Tdigest, .arg.ptr = Pdigest };
     244                 :         76 :         struct buffer_data write_data = { .type = Tout, .arg.i = Iout };
     245                 :            : 
     246                 :         76 :         return buffer_copy(&read_data, &digest, &write_data, limit, err);
     247                 :            : }
     248                 :            : 
     249                 :            : off_t
     250                 :          4 : buffer_copy_IntPtr(int Iin, int Tin,
     251                 :            :                    void *Pdigest, int Tdigest,
     252                 :            :                    void *Pout, int Tout,
     253                 :            :                    off_t limit, struct dpkg_error *err)
     254                 :            : {
     255                 :          4 :         struct buffer_data read_data = { .type = Tin, .arg.i = Iin };
     256                 :          4 :         struct buffer_data digest = { .type = Tdigest, .arg.ptr = Pdigest };
     257                 :          4 :         struct buffer_data write_data = { .type = Tout, .arg.ptr = Pout };
     258                 :            : 
     259                 :          4 :         return buffer_copy(&read_data, &digest, &write_data, limit, err);
     260                 :            : }
     261                 :            : 
     262                 :            : static off_t
     263                 :         27 : buffer_skip(struct buffer_data *input, off_t limit, struct dpkg_error *err)
     264                 :            : {
     265                 :            :         struct buffer_data output;
     266                 :            :         struct buffer_data digest;
     267                 :            : 
     268         [ +  - ]:         27 :         switch (input->type) {
     269                 :         27 :         case BUFFER_READ_FD:
     270         [ +  - ]:         27 :                 if (lseek(input->arg.i, limit, SEEK_CUR) != -1)
     271                 :         27 :                         return limit;
     272         [ #  # ]:          0 :                 if (errno != ESPIPE)
     273                 :          0 :                         return dpkg_put_errno(err, _("failed to seek"));
     274                 :          0 :                 break;
     275                 :          0 :         default:
     276                 :          0 :                 internerr("unknown data type %i", input->type);
     277                 :            :         }
     278                 :            : 
     279                 :          0 :         output.type = BUFFER_WRITE_NULL;
     280                 :          0 :         output.arg.ptr = NULL;
     281                 :          0 :         digest.type = BUFFER_DIGEST_NULL;
     282                 :          0 :         digest.arg.ptr = NULL;
     283                 :            : 
     284                 :          0 :         return buffer_copy(input, &digest, &output, limit, err);
     285                 :            : }
     286                 :            : 
     287                 :            : off_t
     288                 :         27 : buffer_skip_Int(int I, int T, off_t limit, struct dpkg_error *err)
     289                 :            : {
     290                 :         27 :         struct buffer_data input = { .type = T, .arg.i = I };
     291                 :            : 
     292                 :         27 :         return buffer_skip(&input, limit, err);
     293                 :            : }

Generated by: LCOV version 1.16