LCOV - code coverage report
Current view: top level - subprojects/tinycdb-0.81 - cdb_make_put.c (source / functions) Coverage Total Hit
Test: 2 coverage DB files Lines: 14.4 % 118 17
Test Date: 2025-09-15 13:55:46 Functions: 25.0 % 8 2
Branches: 7.5 % 80 6

             Branch data     Line data    Source code
       1                 :             : /* cdb_make_put.c: "advanced" cdb_make_put routine
       2                 :             :  *
       3                 :             :  * This file is a part of tinycdb package.
       4                 :             :  * Copyright (C) 2001-2023 Michael Tokarev <mjt+cdb@corpit.ru>
       5                 :             :  *
       6                 :             :  * Permission is hereby granted, free of charge, to any person obtaining a
       7                 :             :  * copy of this software and associated documentation files (the "Software"),
       8                 :             :  * to deal in the Software without restriction, including without limitation
       9                 :             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      10                 :             :  * and/or sell copies of the Software, and to permit persons to whom the
      11                 :             :  * Software is furnished to do so, subject to the following conditions:
      12                 :             :  *
      13                 :             :  * The above copyright notice and this permission notice shall be included
      14                 :             :  * in all copies or substantial portions of the Software.
      15                 :             :  *
      16                 :             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      17                 :             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      18                 :             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      19                 :             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      20                 :             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      21                 :             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      22                 :             :  * DEALINGS IN THE SOFTWARE.
      23                 :             :  */
      24                 :             : 
      25                 :             : #include <stdlib.h>
      26                 :             : #include <unistd.h>
      27                 :             : #include <assert.h>
      28                 :             : #include "cdb_int.h"
      29                 :             : 
      30                 :             : static void
      31                 :           0 : fixup_rpos(struct cdb_make *cdbmp, unsigned rpos, unsigned rlen) {
      32                 :             :   unsigned i;
      33                 :             :   struct cdb_rl *rl;
      34                 :             :   register struct cdb_rec *rp, *rs;
      35         [ #  # ]:           0 :   for (i = 0; i < 256; ++i) {
      36         [ #  # ]:           0 :     for (rl = cdbmp->cdb_rec[i]; rl; rl = rl->next)
      37         [ #  # ]:           0 :       for (rs = rl->rec, rp = rs + rl->cnt; --rp >= rs;)
      38         [ #  # ]:           0 :         if (rp->rpos <= rpos) goto nexthash;
      39                 :           0 :         else rp->rpos -= rlen;
      40                 :           0 : nexthash:;
      41                 :             :   }
      42                 :           0 : }
      43                 :             : 
      44                 :             : static int
      45                 :           0 : remove_record(struct cdb_make *cdbmp, unsigned rpos, unsigned rlen) {
      46                 :             :   unsigned pos, len;
      47                 :             :   int r, fd;
      48                 :             : 
      49                 :           0 :   len = cdbmp->cdb_dpos - rpos - rlen;
      50                 :           0 :   cdbmp->cdb_dpos -= rlen;
      51         [ #  # ]:           0 :   if (!len)
      52                 :           0 :     return 0;   /* it was the last record, nothing to do */
      53                 :           0 :   pos = rpos;
      54                 :           0 :   fd = cdbmp->cdb_fd;
      55                 :             :   do {
      56                 :           0 :     r = len > sizeof(cdbmp->cdb_buf) ? sizeof(cdbmp->cdb_buf) : len;
      57         [ #  # ]:           0 :     if (lseek(fd, pos + rlen, SEEK_SET) < 0 ||
      58         [ #  # ]:           0 :         (r = read(fd, cdbmp->cdb_buf, r)) <= 0)
      59                 :           0 :       return -1;
      60   [ #  #  #  # ]:           0 :     if (lseek(fd, pos, SEEK_SET) < 0 ||
      61                 :           0 :         _cdb_make_fullwrite(fd, cdbmp->cdb_buf, r) < 0)
      62                 :           0 :       return -1;
      63                 :           0 :     pos += r;
      64                 :           0 :     len -= r;
      65         [ #  # ]:           0 :   } while(len);
      66         [ #  # ]:           0 :   assert(cdbmp->cdb_dpos == pos);
      67                 :           0 :   fixup_rpos(cdbmp, rpos, rlen);
      68                 :           0 :   return 0;
      69                 :             : }
      70                 :             : 
      71                 :             : static int
      72                 :           0 : zerofill_record(struct cdb_make *cdbmp, unsigned rpos, unsigned rlen) {
      73         [ #  # ]:           0 :   if (rpos + rlen == cdbmp->cdb_dpos) {
      74                 :           0 :     cdbmp->cdb_dpos = rpos;
      75                 :           0 :     return 0;
      76                 :             :   }
      77         [ #  # ]:           0 :   if (lseek(cdbmp->cdb_fd, rpos, SEEK_SET) < 0)
      78                 :           0 :     return -1;
      79                 :           0 :   memset(cdbmp->cdb_buf, 0, sizeof(cdbmp->cdb_buf));
      80                 :           0 :   cdb_pack(rlen - 8, cdbmp->cdb_buf + 4);
      81                 :             :   for(;;) {
      82                 :           0 :     rpos = rlen > sizeof(cdbmp->cdb_buf) ? sizeof(cdbmp->cdb_buf) : rlen;
      83         [ #  # ]:           0 :     if (_cdb_make_fullwrite(cdbmp->cdb_fd, cdbmp->cdb_buf, rpos) < 0)
      84                 :           0 :       return -1;
      85                 :           0 :     rlen -= rpos;
      86         [ #  # ]:           0 :     if (!rlen) return 0;
      87                 :           0 :     memset(cdbmp->cdb_buf + 4, 0, 4);
      88                 :             :   }
      89                 :             : }
      90                 :             : 
      91                 :             : /* return: 0 = not found, 1 = error, or record length */
      92                 :             : static unsigned
      93                 :           0 : match(struct cdb_make *cdbmp, unsigned pos, const char *key, unsigned klen)
      94                 :             : {
      95                 :             :   int len;
      96                 :             :   unsigned rlen;
      97         [ #  # ]:           0 :   if (lseek(cdbmp->cdb_fd, pos, SEEK_SET) < 0)
      98                 :           0 :     return 1;
      99         [ #  # ]:           0 :   if (read(cdbmp->cdb_fd, cdbmp->cdb_buf, 8) != 8)
     100                 :           0 :     return 1;
     101         [ #  # ]:           0 :   if (cdb_unpack(cdbmp->cdb_buf) != klen)
     102                 :           0 :     return 0;
     103                 :             : 
     104                 :             :   /* record length; check its validity */
     105                 :           0 :   rlen = cdb_unpack(cdbmp->cdb_buf + 4);
     106         [ #  # ]:           0 :   if (rlen > cdbmp->cdb_dpos - pos - klen - 8)
     107                 :           0 :     return errno = EPROTO, 1;   /* someone changed our file? */
     108                 :           0 :   rlen += klen + 8;
     109                 :             : 
     110         [ #  # ]:           0 :   while(klen) {
     111                 :           0 :     len = klen > sizeof(cdbmp->cdb_buf) ? sizeof(cdbmp->cdb_buf) : klen;
     112                 :           0 :     len = read(cdbmp->cdb_fd, cdbmp->cdb_buf, len);
     113         [ #  # ]:           0 :     if (len <= 0)
     114                 :           0 :       return 1;
     115         [ #  # ]:           0 :     if (memcmp(cdbmp->cdb_buf, key, len) != 0)
     116                 :           0 :       return 0;
     117                 :           0 :     key += len;
     118                 :           0 :     klen -= len;
     119                 :             :   }
     120                 :             : 
     121                 :           0 :   return rlen;
     122                 :             : }
     123                 :             : 
     124                 :             : static int
     125                 :           8 : findrec(struct cdb_make *cdbmp,
     126                 :             :         const void *key, unsigned klen, unsigned hval,
     127                 :             :         enum cdb_put_mode mode)
     128                 :             : {
     129                 :             :   struct cdb_rl *rl;
     130                 :             :   struct cdb_rec *rp, *rs;
     131                 :             :   unsigned r;
     132                 :           8 :   int seeked = 0;
     133                 :           8 :   int ret = 0;
     134         [ -  + ]:           8 :   for(rl = cdbmp->cdb_rec[hval&255]; rl; rl = rl->next)
     135         [ #  # ]:           0 :     for(rs = rl->rec, rp = rs + rl->cnt; --rp >= rs;) {
     136         [ #  # ]:           0 :       if (rp->hval != hval)
     137                 :           0 :         continue;
     138                 :             :       /*XXX this explicit flush may be unnecessary having
     139                 :             :        * smarter match() that looks into cdb_buf too, but
     140                 :             :        * most of a time here spent in finding hash values
     141                 :             :        * (above), not keys */
     142   [ #  #  #  # ]:           0 :       if (!seeked && _cdb_make_flush(cdbmp) < 0)
     143                 :           0 :         return -1;
     144                 :           0 :       seeked = 1;
     145                 :           0 :       r = match(cdbmp, rp->rpos, key, klen);
     146         [ #  # ]:           0 :       if (!r)
     147                 :           0 :         continue;
     148         [ #  # ]:           0 :       if (r == 1)
     149                 :           0 :         return -1;
     150                 :           0 :       ret = 1;
     151      [ #  #  # ]:           0 :       switch(mode) {
     152                 :           0 :       case CDB_FIND_REMOVE:
     153         [ #  # ]:           0 :         if (remove_record(cdbmp, rp->rpos, r) < 0)
     154                 :           0 :           return -1;
     155                 :           0 :         break;
     156                 :           0 :       case CDB_FIND_FILL0:
     157         [ #  # ]:           0 :         if (zerofill_record(cdbmp, rp->rpos, r) < 0)
     158                 :           0 :           return -1;
     159                 :           0 :         break;
     160                 :           0 :       default: goto finish;
     161                 :             :       }
     162                 :           0 :       memmove(rp, rp + 1, (rs + rl->cnt - 1 - rp) * sizeof(*rp));
     163                 :           0 :       --rl->cnt;
     164                 :           0 :       --cdbmp->cdb_rcnt;
     165                 :             :   }
     166                 :           8 : finish:
     167   [ -  +  -  - ]:           8 :   if (seeked && lseek(cdbmp->cdb_fd, cdbmp->cdb_dpos, SEEK_SET) < 0)
     168                 :           0 :     return -1;
     169                 :           8 :   return ret;
     170                 :             : }
     171                 :             : 
     172                 :             : int
     173                 :           0 : cdb_make_find(struct cdb_make *cdbmp,
     174                 :             :               const void *key, unsigned klen,
     175                 :             :               enum cdb_put_mode mode)
     176                 :             : {
     177                 :           0 :   return findrec(cdbmp, key, klen, cdb_hash(key, klen), mode);
     178                 :             : }
     179                 :             : 
     180                 :             : int
     181                 :           0 : cdb_make_exists(struct cdb_make *cdbmp,
     182                 :             :                 const void *key, unsigned klen)
     183                 :             : {
     184                 :           0 :   return cdb_make_find(cdbmp, key, klen, CDB_FIND);
     185                 :             : }
     186                 :             : 
     187                 :             : int
     188                 :           8 : cdb_make_put(struct cdb_make *cdbmp,
     189                 :             :              const void *key, unsigned klen,
     190                 :             :              const void *val, unsigned vlen,
     191                 :             :              enum cdb_put_mode mode)
     192                 :             : {
     193                 :           8 :   unsigned hval = cdb_hash(key, klen);
     194                 :             :   int r;
     195                 :             : 
     196      [ +  -  - ]:           8 :   switch(mode) {
     197                 :           8 :     case CDB_PUT_REPLACE:
     198                 :             :     case CDB_PUT_INSERT:
     199                 :             :     case CDB_PUT_WARN:
     200                 :             :     case CDB_PUT_REPLACE0:
     201                 :           8 :       r = findrec(cdbmp, key, klen, hval, mode);
     202         [ -  + ]:           8 :       if (r < 0)
     203                 :           0 :         return -1;
     204   [ -  +  -  - ]:           8 :       if (r && mode == CDB_PUT_INSERT)
     205                 :           0 :         return errno = EEXIST, 1;
     206                 :           8 :       break;
     207                 :             : 
     208                 :           0 :     case CDB_PUT_ADD:
     209                 :           0 :       r = 0;
     210                 :           0 :       break;
     211                 :             : 
     212                 :           0 :     default:
     213                 :           0 :       return errno = EINVAL, -1;
     214                 :             :   }
     215                 :             : 
     216         [ -  + ]:           8 :   if (_cdb_make_add(cdbmp, hval, key, klen, val, vlen) < 0)
     217                 :           0 :     return -1;
     218                 :             : 
     219                 :           8 :   return r;
     220                 :             : }
     221                 :             : 
        

Generated by: LCOV version 2.0-1