LCOV - code coverage report
Current view: top level - lib/tdb/common - tdb.c (source / functions) Hit Total Coverage
Test: coverage report for vadcx-master-patch-75612 fe003de8 Lines: 439 554 79.2 %
Date: 2024-02-29 22:57:05 Functions: 39 40 97.5 %

          Line data    Source code
       1             :  /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    trivial database library
       5             : 
       6             :    Copyright (C) Andrew Tridgell              1999-2005
       7             :    Copyright (C) Paul `Rusty' Russell              2000
       8             :    Copyright (C) Jeremy Allison                    2000-2003
       9             : 
      10             :      ** NOTE! The following LGPL license applies to the tdb
      11             :      ** library. This does NOT imply that all of Samba is released
      12             :      ** under the LGPL
      13             : 
      14             :    This library is free software; you can redistribute it and/or
      15             :    modify it under the terms of the GNU Lesser General Public
      16             :    License as published by the Free Software Foundation; either
      17             :    version 3 of the License, or (at your option) any later version.
      18             : 
      19             :    This library is distributed in the hope that it will be useful,
      20             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      21             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      22             :    Lesser General Public License for more details.
      23             : 
      24             :    You should have received a copy of the GNU Lesser General Public
      25             :    License along with this library; if not, see <http://www.gnu.org/licenses/>.
      26             : */
      27             : 
      28             : #include "tdb_private.h"
      29             : 
      30             : _PUBLIC_ TDB_DATA tdb_null;
      31             : 
      32             : /*
      33             :   non-blocking increment of the tdb sequence number if the tdb has been opened using
      34             :   the TDB_SEQNUM flag
      35             : */
      36    22134583 : _PUBLIC_ void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)
      37             : {
      38    22134583 :         tdb_off_t seqnum=0;
      39             : 
      40    22134583 :         if (!(tdb->flags & TDB_SEQNUM)) {
      41         153 :                 return;
      42             :         }
      43             : 
      44             :         /* we ignore errors from this, as we have no sane way of
      45             :            dealing with them.
      46             :         */
      47    22134430 :         tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
      48    22134430 :         seqnum++;
      49    22134430 :         tdb_ofs_write(tdb, TDB_SEQNUM_OFS, &seqnum);
      50             : }
      51             : 
      52             : /*
      53             :   increment the tdb sequence number if the tdb has been opened using
      54             :   the TDB_SEQNUM flag
      55             : */
      56    88520511 : static void tdb_increment_seqnum(struct tdb_context *tdb)
      57             : {
      58    88520511 :         if (!(tdb->flags & TDB_SEQNUM)) {
      59    61965253 :                 return;
      60             :         }
      61             : 
      62    23758651 :         if (tdb->transaction != NULL) {
      63    22134416 :                 tdb_increment_seqnum_nonblock(tdb);
      64    22134416 :                 return;
      65             :         }
      66             : 
      67             : #if defined(HAVE___ATOMIC_ADD_FETCH) && defined(HAVE___ATOMIC_ADD_LOAD)
      68     1624235 :         if (tdb->map_ptr != NULL) {
      69     1624235 :                 uint32_t *pseqnum = (uint32_t *)(
      70     1620812 :                         TDB_SEQNUM_OFS + (char *)tdb->map_ptr);
      71     1624235 :                 __atomic_add_fetch(pseqnum, 1, __ATOMIC_SEQ_CST);
      72     1624235 :                 return;
      73             :         }
      74             : #endif
      75             : 
      76           0 :         if (tdb_nest_lock(tdb, TDB_SEQNUM_OFS, F_WRLCK,
      77             :                           TDB_LOCK_WAIT|TDB_LOCK_PROBE) != 0) {
      78           0 :                 return;
      79             :         }
      80             : 
      81           0 :         tdb_increment_seqnum_nonblock(tdb);
      82             : 
      83           0 :         tdb_nest_unlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, false);
      84             : }
      85             : 
      86   499066877 : static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
      87             : {
      88   499066877 :         return memcmp(data.dptr, key.dptr, data.dsize);
      89             : }
      90             : 
      91   965572055 : void tdb_chainwalk_init(struct tdb_chainwalk_ctx *ctx, tdb_off_t ptr)
      92             : {
      93   965572055 :         *ctx = (struct tdb_chainwalk_ctx) { .slow_ptr = ptr };
      94   962029494 : }
      95             : 
      96  2627955051 : bool tdb_chainwalk_check(struct tdb_context *tdb,
      97             :                          struct tdb_chainwalk_ctx *ctx,
      98             :                          tdb_off_t next_ptr)
      99             : {
     100   276651968 :         int ret;
     101             : 
     102  2627955051 :         if (ctx->slow_chase) {
     103  1200776329 :                 ret = tdb_ofs_read(tdb, ctx->slow_ptr, &ctx->slow_ptr);
     104  1200776329 :                 if (ret == -1) {
     105           0 :                         return false;
     106             :                 }
     107             :         }
     108  2627955051 :         ctx->slow_chase = !ctx->slow_chase;
     109             : 
     110  2627955051 :         if (next_ptr == ctx->slow_ptr) {
     111           2 :                 tdb->ecode = TDB_ERR_CORRUPT;
     112           2 :                 TDB_LOG((tdb, TDB_DEBUG_ERROR,
     113             :                          "tdb_chainwalk_check: circular chain\n"));
     114           2 :                 return false;
     115             :         }
     116             : 
     117  2351303081 :         return true;
     118             : }
     119             : 
     120             : /* Returns 0 on fail.  On success, return offset of record, and fills
     121             :    in rec */
     122   818470434 : static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
     123             :                         struct tdb_record *r)
     124             : {
     125    27675953 :         tdb_off_t rec_ptr;
     126    27675953 :         struct tdb_chainwalk_ctx chainwalk;
     127             : 
     128             :         /* read in the hash top */
     129   818470434 :         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
     130           0 :                 return 0;
     131             : 
     132   818470434 :         tdb_chainwalk_init(&chainwalk, rec_ptr);
     133             : 
     134             :         /* keep looking until we find the right record */
     135  2785705599 :         while (rec_ptr) {
     136   217673844 :                 bool ok;
     137             : 
     138  2443151458 :                 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
     139           0 :                         return 0;
     140             : 
     141  2443151458 :                 if (!TDB_DEAD(r) && hash==r->full_hash
     142   499066890 :                     && key.dsize==r->key_len
     143   499066877 :                     && tdb_parse_data(tdb, key, rec_ptr + sizeof(*r),
     144             :                                       r->key_len, tdb_key_compare,
     145             :                                       NULL) == 0) {
     146   475916292 :                         return rec_ptr;
     147             :                 }
     148  1967235166 :                 rec_ptr = r->next;
     149             : 
     150  1967235166 :                 ok = tdb_chainwalk_check(tdb, &chainwalk, rec_ptr);
     151  1967235166 :                 if (!ok) {
     152           1 :                         return 0;
     153             :                 }
     154             :         }
     155   342554141 :         tdb->ecode = TDB_ERR_NOEXIST;
     156   342554141 :         return 0;
     157             : }
     158             : 
     159             : /* As tdb_find, but if you succeed, keep the lock */
     160   761506249 : tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
     161             :                            struct tdb_record *rec)
     162             : {
     163    25979497 :         uint32_t rec_ptr;
     164             : 
     165   761506249 :         if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
     166           0 :                 return 0;
     167   761506249 :         if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
     168   300906214 :                 tdb_unlock(tdb, BUCKET(hash), locktype);
     169   735526752 :         return rec_ptr;
     170             : }
     171             : 
     172             : static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
     173             : 
     174             : struct tdb_update_hash_state {
     175             :         const TDB_DATA *dbufs;
     176             :         int num_dbufs;
     177             :         tdb_len_t dbufs_len;
     178             : };
     179             : 
     180     7617173 : static int tdb_update_hash_cmp(TDB_DATA key, TDB_DATA data, void *private_data)
     181             : {
     182     7617173 :         struct tdb_update_hash_state *state = private_data;
     183     7617173 :         unsigned char *dptr = data.dptr;
     184      311919 :         int i;
     185             : 
     186     7617173 :         if (state->dbufs_len != data.dsize) {
     187           0 :                 return -1;
     188             :         }
     189             : 
     190    10517810 :         for (i=0; i<state->num_dbufs; i++) {
     191     8336567 :                 TDB_DATA dbuf = state->dbufs[i];
     192     8336567 :                 if( dbuf.dsize > 0) {
     193      318049 :                         int ret;
     194     8336177 :                         ret = memcmp(dptr, dbuf.dptr, dbuf.dsize);
     195     8336177 :                         if (ret != 0) {
     196     5538762 :                                 return -1;
     197             :                         }
     198     2900247 :                         dptr += dbuf.dsize;
     199             :                 }
     200             :         }
     201             : 
     202     2078411 :         return 0;
     203             : }
     204             : 
     205             : /* update an entry in place - this only works if the new data size
     206             :    is <= the old data size and the key exists.
     207             :    on failure return -1.
     208             : */
     209    56964185 : static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key,
     210             :                            uint32_t hash,
     211             :                            const TDB_DATA *dbufs, int num_dbufs,
     212             :                            tdb_len_t dbufs_len)
     213             : {
     214     1696456 :         struct tdb_record rec;
     215     1696456 :         tdb_off_t rec_ptr, ofs;
     216     1696456 :         int i;
     217             : 
     218             :         /* find entry */
     219    56964185 :         if (!(rec_ptr = tdb_find(tdb, key, hash, &rec)))
     220    40893486 :                 return -1;
     221             : 
     222             :         /* it could be an exact duplicate of what is there - this is
     223             :          * surprisingly common (eg. with a ldb re-index). */
     224    15316257 :         if (rec.data_len == dbufs_len) {
     225     7617173 :                 struct tdb_update_hash_state state = {
     226             :                         .dbufs = dbufs, .num_dbufs = num_dbufs,
     227             :                         .dbufs_len = dbufs_len
     228             :                 };
     229      311919 :                 int ret;
     230             : 
     231     7617173 :                 ret = tdb_parse_record(tdb, key, tdb_update_hash_cmp, &state);
     232     7617173 :                 if (ret == 0) {
     233     2181243 :                         return 0;
     234             :                 }
     235             :         }
     236             : 
     237             :         /* must be long enough key, data and tailer */
     238    13135014 :         if (rec.rec_len < key.dsize + dbufs_len + sizeof(tdb_off_t)) {
     239     1313376 :                 tdb->ecode = TDB_SUCCESS; /* Not really an error */
     240     1313376 :                 return -1;
     241             :         }
     242             : 
     243    11821638 :         ofs = rec_ptr + sizeof(rec) + rec.key_len;
     244             : 
     245    28379620 :         for (i=0; i<num_dbufs; i++) {
     246    16557982 :                 TDB_DATA dbuf = dbufs[i];
     247      819637 :                 int ret;
     248             : 
     249    16557982 :                 ret = tdb->methods->tdb_write(tdb, ofs, dbuf.dptr, dbuf.dsize);
     250    16557982 :                 if (ret == -1) {
     251     1696456 :                         return -1;
     252             :                 }
     253    16557982 :                 ofs += dbuf.dsize;
     254             :         }
     255             : 
     256    11821638 :         if (dbufs_len != rec.data_len) {
     257             :                 /* update size */
     258     6385708 :                 rec.data_len = dbufs_len;
     259     6385708 :                 return tdb_rec_write(tdb, rec_ptr, &rec);
     260             :         }
     261             : 
     262     5226843 :         return 0;
     263             : }
     264             : 
     265             : /* find an entry in the database given a key */
     266             : /* If an entry doesn't exist tdb_err will be set to
     267             :  * TDB_ERR_NOEXIST. If a key has no data attached
     268             :  * then the TDB_DATA will have zero length but
     269             :  * a non-zero pointer
     270             :  */
     271   154787531 : static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
     272             : {
     273    12557974 :         tdb_off_t rec_ptr;
     274    12557974 :         struct tdb_record rec;
     275    12557974 :         TDB_DATA ret;
     276    12557974 :         uint32_t hash;
     277             : 
     278             :         /* find which hash bucket it is in */
     279   154787531 :         hash = tdb->hash_fn(&key);
     280   154787531 :         if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec)))
     281    99619298 :                 return tdb_null;
     282             : 
     283    55168233 :         ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
     284             :                                   rec.data_len);
     285    55168233 :         ret.dsize = rec.data_len;
     286    55168233 :         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
     287    55168233 :         return ret;
     288             : }
     289             : 
     290   154718491 : _PUBLIC_ TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
     291             : {
     292   154718491 :         TDB_DATA ret = _tdb_fetch(tdb, key);
     293             : 
     294    12557676 :         tdb_trace_1rec_retrec(tdb, "tdb_fetch", key, ret);
     295   154718491 :         return ret;
     296             : }
     297             : 
     298             : /*
     299             :  * Find an entry in the database and hand the record's data to a parsing
     300             :  * function. The parsing function is executed under the chain read lock, so it
     301             :  * should be fast and should not block on other syscalls.
     302             :  *
     303             :  * DON'T CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS.
     304             :  *
     305             :  * For mmapped tdb's that do not have a transaction open it points the parsing
     306             :  * function directly at the mmap area, it avoids the malloc/memcpy in this
     307             :  * case. If a transaction is open or no mmap is available, it has to do
     308             :  * malloc/read/parse/free.
     309             :  *
     310             :  * This is interesting for all readers of potentially large data structures in
     311             :  * the tdb records, ldb indexes being one example.
     312             :  *
     313             :  * Return -1 if the record was not found.
     314             :  */
     315             : 
     316   533093135 : _PUBLIC_ int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
     317             :                      int (*parser)(TDB_DATA key, TDB_DATA data,
     318             :                                    void *private_data),
     319             :                      void *private_data)
     320             : {
     321     9897926 :         tdb_off_t rec_ptr;
     322     9897926 :         struct tdb_record rec;
     323     9897926 :         int ret;
     324     9897926 :         uint32_t hash;
     325             : 
     326             :         /* find which hash bucket it is in */
     327   533093135 :         hash = tdb->hash_fn(&key);
     328             : 
     329   533093135 :         if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
     330             :                 /* record not found */
     331     1992661 :                 tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1);
     332   131670714 :                 tdb->ecode = TDB_ERR_NOEXIST;
     333   131670714 :                 return -1;
     334             :         }
     335     7905265 :         tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0);
     336             : 
     337   401422421 :         ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
     338             :                              rec.data_len, parser, private_data);
     339             : 
     340   401422421 :         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
     341             : 
     342   401422421 :         return ret;
     343             : }
     344             : 
     345             : /* check if an entry in the database exists
     346             : 
     347             :    note that 1 is returned if the key is found and 0 is returned if not found
     348             :    this doesn't match the conventions in the rest of this module, but is
     349             :    compatible with gdbm
     350             : */
     351    27662245 : static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
     352             : {
     353     2581328 :         struct tdb_record rec;
     354             : 
     355    27662245 :         if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
     356    25061010 :                 return 0;
     357       20053 :         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
     358       20053 :         return 1;
     359             : }
     360             : 
     361       78582 : _PUBLIC_ int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
     362             : {
     363       78582 :         uint32_t hash = tdb->hash_fn(&key);
     364        2598 :         int ret;
     365             : 
     366       78582 :         ret = tdb_exists_hash(tdb, key, hash);
     367        2598 :         tdb_trace_1rec_ret(tdb, "tdb_exists", key, ret);
     368       78582 :         return ret;
     369             : }
     370             : 
     371             : /*
     372             :  * Move a dead record to the freelist. The hash chain and freelist
     373             :  * must be locked.
     374             :  */
     375     3006949 : static int tdb_del_dead(struct tdb_context *tdb,
     376             :                         uint32_t last_ptr,
     377             :                         uint32_t rec_ptr,
     378             :                         struct tdb_record *rec,
     379             :                         bool *deleted)
     380             : {
     381      208613 :         int ret;
     382             : 
     383     3006949 :         ret = tdb_write_lock_record(tdb, rec_ptr);
     384     3006949 :         if (ret == -1) {
     385             :                 /* Someone traversing here: Just leave it dead */
     386       53034 :                 return 0;
     387             :         }
     388     2918903 :         ret = tdb_write_unlock_record(tdb, rec_ptr);
     389     2918903 :         if (ret == -1) {
     390           0 :                 return -1;
     391             :         }
     392     2918903 :         ret = tdb_ofs_write(tdb, last_ptr, &rec->next);
     393     2918903 :         if (ret == -1) {
     394           0 :                 return -1;
     395             :         }
     396             : 
     397     2918903 :         *deleted = true;
     398             : 
     399     2918903 :         ret = tdb_free(tdb, rec_ptr, rec);
     400     2918903 :         return ret;
     401             : }
     402             : 
     403             : /*
     404             :  * Walk the hash chain and leave tdb->max_dead_records around. Move
     405             :  * the rest of dead records to the freelist.
     406             :  */
     407    73789314 : int tdb_trim_dead(struct tdb_context *tdb, uint32_t hash)
     408             : {
     409     3542561 :         struct tdb_chainwalk_ctx chainwalk;
     410     3542561 :         struct tdb_record rec;
     411     3542561 :         tdb_off_t last_ptr, rec_ptr;
     412    73789314 :         bool locked_freelist = false;
     413    73789314 :         int num_dead = 0;
     414     3542561 :         int ret;
     415             : 
     416    73789314 :         last_ptr = TDB_HASH_TOP(hash);
     417             : 
     418             :         /*
     419             :          * Init chainwalk with the pointer to the hash top. It might
     420             :          * be that the very first record in the chain is a dead one
     421             :          * that we have to delete.
     422             :          */
     423    73789314 :         tdb_chainwalk_init(&chainwalk, last_ptr);
     424             : 
     425    73789314 :         ret = tdb_ofs_read(tdb, last_ptr, &rec_ptr);
     426    73789314 :         if (ret == -1) {
     427           0 :                 return -1;
     428             :         }
     429             : 
     430   345586852 :         while (rec_ptr != 0) {
     431   271797538 :                 bool deleted = false;
     432    38643408 :                 uint32_t next;
     433             : 
     434   271797538 :                 ret = tdb_rec_read(tdb, rec_ptr, &rec);
     435   271797538 :                 if (ret == -1) {
     436           0 :                         goto fail;
     437             :                 }
     438             : 
     439             :                 /*
     440             :                  * Make a copy of rec.next: Further down we might
     441             :                  * delete and put the record on the freelist. Make
     442             :                  * sure that modifications in that code path can't
     443             :                  * break the chainwalk here.
     444             :                  */
     445   271797538 :                 next = rec.next;
     446             : 
     447   271797538 :                 if (rec.magic == TDB_DEAD_MAGIC) {
     448     4458933 :                         num_dead += 1;
     449             : 
     450     4458933 :                         if (num_dead > tdb->max_dead_records) {
     451             : 
     452     3006949 :                                 if (!locked_freelist) {
     453             :                                         /*
     454             :                                          * Lock the freelist only if
     455             :                                          * it's really required.
     456             :                                          */
     457     2934609 :                                         ret = tdb_lock(tdb, -1, F_WRLCK);
     458     2934609 :                                         if (ret == -1) {
     459           0 :                                                 goto fail;
     460             :                                         };
     461     2755457 :                                         locked_freelist = true;
     462             :                                 }
     463             : 
     464     3006949 :                                 ret = tdb_del_dead(
     465             :                                         tdb,
     466             :                                         last_ptr,
     467             :                                         rec_ptr,
     468             :                                         &rec,
     469             :                                         &deleted);
     470             : 
     471     3006949 :                                 if (ret == -1) {
     472           0 :                                         goto fail;
     473             :                                 }
     474             :                         }
     475             :                 }
     476             : 
     477             :                 /*
     478             :                  * Don't do the chainwalk check if "rec_ptr" was
     479             :                  * deleted. We reduced the chain, and the chainwalk
     480             :                  * check might catch up early. Imagine a valid chain
     481             :                  * with just dead records: We never can bump the
     482             :                  * "slow" pointer in chainwalk_check, as there isn't
     483             :                  * anything left to jump to and compare.
     484             :                  */
     485   271797538 :                 if (!deleted) {
     486    38469807 :                         bool ok;
     487             : 
     488   268878635 :                         last_ptr = rec_ptr;
     489             : 
     490   268878635 :                         ok = tdb_chainwalk_check(tdb, &chainwalk, next);
     491   268878635 :                         if (!ok) {
     492           0 :                                 ret = -1;
     493           0 :                                 goto fail;
     494             :                         }
     495             :                 }
     496   271797538 :                 rec_ptr = next;
     497             :         }
     498    70246753 :         ret = 0;
     499    73789314 : fail:
     500    73789314 :         if (locked_freelist) {
     501     2934609 :                 tdb_unlock(tdb, -1, F_WRLCK);
     502             :         }
     503    70246753 :         return ret;
     504             : }
     505             : 
     506             : /* delete an entry in the database given a key */
     507    45963337 : static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
     508             : {
     509      942269 :         tdb_off_t rec_ptr;
     510      942269 :         struct tdb_record rec;
     511      942269 :         int ret;
     512             : 
     513    45963337 :         if (tdb->read_only || tdb->traverse_read) {
     514           0 :                 tdb->ecode = TDB_ERR_RDONLY;
     515           0 :                 return -1;
     516             :         }
     517             : 
     518    45963337 :         rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK, &rec);
     519    45963337 :         if (rec_ptr == 0) {
     520    41211102 :                 return -1;
     521             :         }
     522             : 
     523             :         /*
     524             :          * Mark the record dead
     525             :          */
     526     3989327 :         rec.magic = TDB_DEAD_MAGIC;
     527     3989327 :         ret = tdb_rec_write(tdb, rec_ptr, &rec);
     528     3989327 :         if (ret == -1) {
     529           0 :                 goto done;
     530             :         }
     531             : 
     532     3989327 :         tdb_increment_seqnum(tdb);
     533             : 
     534     3989327 :         ret = tdb_trim_dead(tdb, hash);
     535     3989327 : done:
     536     3989327 :         if (tdb_unlock(tdb, BUCKET(hash), F_WRLCK) != 0)
     537           0 :                 TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n"));
     538     3809966 :         return ret;
     539             : }
     540             : 
     541     3002244 : _PUBLIC_ int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
     542             : {
     543     3002244 :         uint32_t hash = tdb->hash_fn(&key);
     544      156627 :         int ret;
     545             : 
     546     3002244 :         ret = tdb_delete_hash(tdb, key, hash);
     547      156627 :         tdb_trace_1rec_ret(tdb, "tdb_delete", key, ret);
     548     3002244 :         return ret;
     549             : }
     550             : 
     551             : /*
     552             :  * See if we have a dead record around with enough space
     553             :  */
     554     1106470 : tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
     555             :                         struct tdb_record *r, tdb_len_t length,
     556             :                         tdb_off_t *p_last_ptr)
     557             : {
     558        5328 :         tdb_off_t rec_ptr, last_ptr;
     559        5328 :         struct tdb_chainwalk_ctx chainwalk;
     560     1106470 :         tdb_off_t best_rec_ptr = 0;
     561     1106470 :         tdb_off_t best_last_ptr = 0;
     562     1106470 :         struct tdb_record best = { .rec_len = UINT32_MAX };
     563             : 
     564     1106470 :         length += sizeof(tdb_off_t); /* tailer */
     565             : 
     566     1106470 :         last_ptr = TDB_HASH_TOP(hash);
     567             : 
     568             :         /* read in the hash top */
     569     1106470 :         if (tdb_ofs_read(tdb, last_ptr, &rec_ptr) == -1)
     570           0 :                 return 0;
     571             : 
     572     1106470 :         tdb_chainwalk_init(&chainwalk, rec_ptr);
     573             : 
     574             :         /* keep looking until we find the right record */
     575     2222374 :         while (rec_ptr) {
     576        1784 :                 bool ok;
     577             : 
     578     1115904 :                 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
     579           0 :                         return 0;
     580             : 
     581     1115904 :                 if (TDB_DEAD(r) && (r->rec_len >= length) &&
     582      968499 :                     (r->rec_len < best.rec_len)) {
     583      733736 :                         best_rec_ptr = rec_ptr;
     584      733736 :                         best_last_ptr = last_ptr;
     585      733736 :                         best = *r;
     586             :                 }
     587     1115904 :                 last_ptr = rec_ptr;
     588     1115904 :                 rec_ptr = r->next;
     589             : 
     590     1115904 :                 ok = tdb_chainwalk_check(tdb, &chainwalk, rec_ptr);
     591     1115904 :                 if (!ok) {
     592           0 :                         return 0;
     593             :                 }
     594             :         }
     595             : 
     596     1106470 :         if (best.rec_len == UINT32_MAX) {
     597      373853 :                 return 0;
     598             :         }
     599             : 
     600      728317 :         *r = best;
     601      728317 :         *p_last_ptr = best_last_ptr;
     602      728317 :         return best_rec_ptr;
     603             : }
     604             : 
     605    84547848 : static int _tdb_storev(struct tdb_context *tdb, TDB_DATA key,
     606             :                        const TDB_DATA *dbufs, int num_dbufs,
     607             :                        int flag, uint32_t hash)
     608             : {
     609     4275186 :         struct tdb_record rec;
     610     4275186 :         tdb_off_t rec_ptr, ofs;
     611     4275186 :         tdb_len_t rec_len, dbufs_len;
     612     4275186 :         int i;
     613    84547848 :         int ret = -1;
     614             : 
     615    84547848 :         dbufs_len = 0;
     616             : 
     617   177053464 :         for (i=0; i<num_dbufs; i++) {
     618    92505616 :                 size_t dsize = dbufs[i].dsize;
     619             : 
     620    92505616 :                 if ((dsize != 0) && (dbufs[i].dptr == NULL)) {
     621           0 :                         tdb->ecode = TDB_ERR_EINVAL;
     622           0 :                         goto fail;
     623             :                 }
     624             : 
     625    92505616 :                 dbufs_len += dsize;
     626    92505616 :                 if (dbufs_len < dsize) {
     627           0 :                         tdb->ecode = TDB_ERR_OOM;
     628           0 :                         goto fail;
     629             :                 }
     630             :         }
     631             : 
     632    84547848 :         rec_len = key.dsize + dbufs_len;
     633    84547848 :         if ((rec_len < key.dsize) || (rec_len < dbufs_len)) {
     634           0 :                 tdb->ecode = TDB_ERR_OOM;
     635           0 :                 goto fail;
     636             :         }
     637             : 
     638             :         /* check for it existing, on insert. */
     639    84547848 :         if (flag == TDB_INSERT) {
     640    27583663 :                 if (tdb_exists_hash(tdb, key, hash)) {
     641       16452 :                         tdb->ecode = TDB_ERR_EXISTS;
     642       16452 :                         goto fail;
     643             :                 }
     644             :         } else {
     645             :                 /* first try in-place update, on modify or replace. */
     646    56964185 :                 if (tdb_update_hash(tdb, key, hash, dbufs, num_dbufs,
     647             :                                     dbufs_len) == 0) {
     648    14002881 :                         goto done;
     649             :                 }
     650    42961304 :                 if (tdb->ecode == TDB_ERR_NOEXIST &&
     651             :                     flag == TDB_MODIFY) {
     652             :                         /* if the record doesn't exist and we are in TDB_MODIFY mode then
     653             :                          we should fail the store */
     654         211 :                         goto fail;
     655             :                 }
     656             :         }
     657             :         /* reset the error code potentially set by the tdb_update_hash() */
     658    70528304 :         tdb->ecode = TDB_SUCCESS;
     659             : 
     660             :         /* delete any existing record - if it doesn't exist we don't
     661             :            care.  Doing this first reduces fragmentation, and avoids
     662             :            coalescing with `allocated' block before it's updated. */
     663    70528304 :         if (flag != TDB_INSERT)
     664    42961093 :                 tdb_delete_hash(tdb, key, hash);
     665             : 
     666             :         /* we have to allocate some space */
     667    70528304 :         rec_ptr = tdb_allocate(tdb, hash, rec_len, &rec);
     668             : 
     669    70528304 :         if (rec_ptr == 0) {
     670           1 :                 goto fail;
     671             :         }
     672             : 
     673             :         /* Read hash top into next ptr */
     674    70528303 :         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
     675           0 :                 goto fail;
     676             : 
     677    70528303 :         rec.key_len = key.dsize;
     678    70528303 :         rec.data_len = dbufs_len;
     679    70528303 :         rec.full_hash = hash;
     680    70528303 :         rec.magic = TDB_MAGIC;
     681             : 
     682    70528303 :         ofs = rec_ptr;
     683             : 
     684             :         /* write out and point the top of the hash chain at it */
     685    70528303 :         ret = tdb_rec_write(tdb, ofs, &rec);
     686    70528303 :         if (ret == -1) {
     687           0 :                 goto fail;
     688             :         }
     689    70528303 :         ofs += sizeof(rec);
     690             : 
     691    70528303 :         ret = tdb->methods->tdb_write(tdb, ofs, key.dptr, key.dsize);
     692    70528303 :         if (ret == -1) {
     693           0 :                 goto fail;
     694             :         }
     695    70528303 :         ofs += key.dsize;
     696             : 
     697   144185661 :         for (i=0; i<num_dbufs; i++) {
     698    73657358 :                 if (dbufs[i].dsize == 0) {
     699      890170 :                         continue;
     700             :                 }
     701             : 
     702    72767188 :                 ret = tdb->methods->tdb_write(tdb, ofs, dbufs[i].dptr,
     703    69360530 :                                               dbufs[i].dsize);
     704    72767188 :                 if (ret == -1) {
     705           0 :                         goto fail;
     706             :                 }
     707    72767188 :                 ofs += dbufs[i].dsize;
     708             :         }
     709             : 
     710    70528303 :         ret = tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr);
     711    70528303 :         if (ret == -1) {
     712             :                 /* Need to tdb_unallocate() here */
     713           0 :                 goto fail;
     714             :         }
     715             : 
     716    70528303 :  done:
     717    84531184 :         ret = 0;
     718    80272662 :  fail:
     719    80272830 :         if (ret == 0) {
     720    84531184 :                 tdb_increment_seqnum(tdb);
     721             :         }
     722    84547848 :         return ret;
     723             : }
     724             : 
     725    76888504 : static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
     726             :                       TDB_DATA dbuf, int flag, uint32_t hash)
     727             : {
     728    76888504 :         return _tdb_storev(tdb, key, &dbuf, 1, flag, hash);
     729             : }
     730             : 
     731             : /* store an element in the database, replacing any existing element
     732             :    with the same key
     733             : 
     734             :    return 0 on success, -1 on failure
     735             : */
     736    76888615 : _PUBLIC_ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
     737             : {
     738     4129398 :         uint32_t hash;
     739     4129398 :         int ret;
     740             : 
     741    76888615 :         if (tdb->read_only || tdb->traverse_read) {
     742         111 :                 tdb->ecode = TDB_ERR_RDONLY;
     743           0 :                 tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, -1);
     744         111 :                 return -1;
     745             :         }
     746             : 
     747             :         /* find which hash bucket it is in */
     748    76888504 :         hash = tdb->hash_fn(&key);
     749    76888504 :         if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
     750           0 :                 return -1;
     751             : 
     752    76888504 :         ret = _tdb_store(tdb, key, dbuf, flag, hash);
     753     4129398 :         tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, ret);
     754    76888504 :         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
     755    76888504 :         return ret;
     756             : }
     757             : 
     758     7590304 : _PUBLIC_ int tdb_storev(struct tdb_context *tdb, TDB_DATA key,
     759             :                         const TDB_DATA *dbufs, int num_dbufs, int flag)
     760             : {
     761      145490 :         uint32_t hash;
     762      145490 :         int ret;
     763             : 
     764     7590304 :         if (tdb->read_only || tdb->traverse_read) {
     765           0 :                 tdb->ecode = TDB_ERR_RDONLY;
     766           0 :                 tdb_trace_1plusn_rec_flag_ret(tdb, "tdb_storev", key,
     767           0 :                                               dbufs, num_dbufs, flag, -1);
     768           0 :                 return -1;
     769             :         }
     770             : 
     771             :         /* find which hash bucket it is in */
     772     7590304 :         hash = tdb->hash_fn(&key);
     773     7590304 :         if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
     774           0 :                 return -1;
     775             : 
     776     7590304 :         ret = _tdb_storev(tdb, key, dbufs, num_dbufs, flag, hash);
     777      145490 :         tdb_trace_1plusn_rec_flag_ret(tdb, "tdb_storev", key,
     778      145490 :                                       dbufs, num_dbufs, flag, -1);
     779     7590304 :         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
     780     7590304 :         return ret;
     781             : }
     782             : 
     783             : /* Append to an entry. Create if not exist. */
     784       69040 : _PUBLIC_ int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
     785             : {
     786         298 :         uint32_t hash;
     787         298 :         TDB_DATA dbufs[2];
     788       69040 :         int ret = -1;
     789             : 
     790             :         /* find which hash bucket it is in */
     791       69040 :         hash = tdb->hash_fn(&key);
     792       69040 :         if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
     793           0 :                 return -1;
     794             : 
     795       69040 :         dbufs[0] = _tdb_fetch(tdb, key);
     796       69040 :         dbufs[1] = new_dbuf;
     797             : 
     798       69040 :         ret = _tdb_storev(tdb, key, dbufs, 2, 0, hash);
     799         298 :         tdb_trace_2rec_retrec(tdb, "tdb_append", key, dbufs[0], dbufs[1]);
     800             : 
     801       69040 :         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
     802       69040 :         SAFE_FREE(dbufs[0].dptr);
     803       68742 :         return ret;
     804             : }
     805             : 
     806             : 
     807             : /*
     808             :   return the name of the current tdb file
     809             :   useful for external logging functions
     810             : */
     811     4194475 : _PUBLIC_ const char *tdb_name(struct tdb_context *tdb)
     812             : {
     813     4194475 :         return tdb->name;
     814             : }
     815             : 
     816             : /*
     817             :   return the underlying file descriptor being used by tdb, or -1
     818             :   useful for external routines that want to check the device/inode
     819             :   of the fd
     820             : */
     821     1660182 : _PUBLIC_ int tdb_fd(struct tdb_context *tdb)
     822             : {
     823     1660182 :         return tdb->fd;
     824             : }
     825             : 
     826             : /*
     827             :   return the current logging function
     828             :   useful for external tdb routines that wish to log tdb errors
     829             : */
     830           0 : _PUBLIC_ tdb_log_func tdb_log_fn(struct tdb_context *tdb)
     831             : {
     832           0 :         return tdb->log.log_fn;
     833             : }
     834             : 
     835             : 
     836             : /*
     837             :   get the tdb sequence number. Only makes sense if the writers opened
     838             :   with TDB_SEQNUM set. Note that this sequence number will wrap quite
     839             :   quickly, so it should only be used for a 'has something changed'
     840             :   test, not for code that relies on the count of the number of changes
     841             :   made. If you want a counter then use a tdb record.
     842             : 
     843             :   The aim of this sequence number is to allow for a very lightweight
     844             :   test of a possible tdb change.
     845             : */
     846   198864056 : _PUBLIC_ int tdb_get_seqnum(struct tdb_context *tdb)
     847             : {
     848   198864056 :         tdb_off_t seqnum=0;
     849             : 
     850   198864056 :         if (tdb->transaction != NULL) {
     851    63978508 :                 tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
     852    63978508 :                 return seqnum;
     853             :         }
     854             : 
     855             : #if defined(HAVE___ATOMIC_ADD_FETCH) && defined(HAVE___ATOMIC_ADD_LOAD)
     856   134885548 :         if (tdb->map_ptr != NULL) {
     857   134885548 :                 uint32_t *pseqnum = (uint32_t *)(
     858   130023804 :                         TDB_SEQNUM_OFS + (char *)tdb->map_ptr);
     859     4861744 :                 uint32_t ret;
     860   134885548 :                 __atomic_load(pseqnum, &ret,__ATOMIC_SEQ_CST);
     861   134885548 :                 return ret;
     862             :         }
     863             : #endif
     864             : 
     865           0 :         tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
     866           0 :         return seqnum;
     867             : }
     868             : 
     869         632 : _PUBLIC_ int tdb_hash_size(struct tdb_context *tdb)
     870             : {
     871         632 :         return tdb->hash_size;
     872             : }
     873             : 
     874           6 : _PUBLIC_ size_t tdb_map_size(struct tdb_context *tdb)
     875             : {
     876           6 :         return tdb->map_size;
     877             : }
     878             : 
     879           6 : _PUBLIC_ int tdb_get_flags(struct tdb_context *tdb)
     880             : {
     881           6 :         return tdb->flags;
     882             : }
     883             : 
     884           4 : _PUBLIC_ void tdb_add_flags(struct tdb_context *tdb, unsigned flags)
     885             : {
     886           4 :         if ((flags & TDB_ALLOW_NESTING) &&
     887           0 :             (flags & TDB_DISALLOW_NESTING)) {
     888           0 :                 tdb->ecode = TDB_ERR_NESTING;
     889           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_add_flags: "
     890             :                         "allow_nesting and disallow_nesting are not allowed together!"));
     891           0 :                 return;
     892             :         }
     893             : 
     894           4 :         if (flags & TDB_ALLOW_NESTING) {
     895           0 :                 tdb->flags &= ~TDB_DISALLOW_NESTING;
     896             :         }
     897           4 :         if (flags & TDB_DISALLOW_NESTING) {
     898           0 :                 tdb->flags &= ~TDB_ALLOW_NESTING;
     899             :         }
     900             : 
     901           4 :         tdb->flags |= flags;
     902             : }
     903             : 
     904           4 : _PUBLIC_ void tdb_remove_flags(struct tdb_context *tdb, unsigned flags)
     905             : {
     906           4 :         if ((flags & TDB_ALLOW_NESTING) &&
     907           0 :             (flags & TDB_DISALLOW_NESTING)) {
     908           0 :                 tdb->ecode = TDB_ERR_NESTING;
     909           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_remove_flags: "
     910             :                         "allow_nesting and disallow_nesting are not allowed together!"));
     911           0 :                 return;
     912             :         }
     913             : 
     914           4 :         if ((flags & TDB_NOLOCK) &&
     915           0 :             (tdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) &&
     916           0 :             (tdb->mutexes == NULL)) {
     917           0 :                 tdb->ecode = TDB_ERR_LOCK;
     918           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_remove_flags: "
     919             :                          "Can not remove NOLOCK flag on mutexed databases"));
     920           0 :                 return;
     921             :         }
     922             : 
     923           4 :         if (flags & TDB_ALLOW_NESTING) {
     924           0 :                 tdb->flags |= TDB_DISALLOW_NESTING;
     925             :         }
     926           4 :         if (flags & TDB_DISALLOW_NESTING) {
     927           0 :                 tdb->flags |= TDB_ALLOW_NESTING;
     928             :         }
     929             : 
     930           4 :         tdb->flags &= ~flags;
     931             : }
     932             : 
     933             : 
     934             : /*
     935             :   enable sequence number handling on an open tdb
     936             : */
     937           2 : _PUBLIC_ void tdb_enable_seqnum(struct tdb_context *tdb)
     938             : {
     939           2 :         tdb->flags |= TDB_SEQNUM;
     940           2 : }
     941             : 
     942             : 
     943             : /*
     944             :   add a region of the file to the freelist. Length is the size of the region in bytes,
     945             :   which includes the free list header that needs to be added
     946             :  */
     947         317 : static int tdb_free_region(struct tdb_context *tdb, tdb_off_t offset, ssize_t length)
     948             : {
     949          17 :         struct tdb_record rec;
     950         317 :         if (length <= sizeof(rec)) {
     951             :                 /* the region is not worth adding */
     952         103 :                 return 0;
     953             :         }
     954         206 :         if (length + offset > tdb->map_size) {
     955           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: adding region beyond end of file\n"));
     956           0 :                 return -1;
     957             :         }
     958         206 :         memset(&rec,'\0',sizeof(rec));
     959         206 :         rec.rec_len = length - sizeof(rec);
     960         206 :         if (tdb_free(tdb, offset, &rec) == -1) {
     961           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: failed to add free record\n"));
     962           0 :                 return -1;
     963             :         }
     964         197 :         return 0;
     965             : }
     966             : 
     967             : /*
     968             :   wipe the entire database, deleting all records. This can be done
     969             :   very fast by using a allrecord lock. The entire data portion of the
     970             :   file becomes a single entry in the freelist.
     971             : 
     972             :   This code carefully steps around the recovery area, leaving it alone
     973             :  */
     974         223 : _PUBLIC_ int tdb_wipe_all(struct tdb_context *tdb)
     975             : {
     976          12 :         uint32_t i;
     977         223 :         tdb_off_t offset = 0;
     978          12 :         ssize_t data_len;
     979          12 :         tdb_off_t recovery_head;
     980         223 :         tdb_len_t recovery_size = 0;
     981             : 
     982         223 :         if (tdb_lockall(tdb) != 0) {
     983          58 :                 return -1;
     984             :         }
     985             : 
     986          12 :         tdb_trace(tdb, "tdb_wipe_all");
     987             : 
     988             :         /* see if the tdb has a recovery area, and remember its size
     989             :            if so. We don't want to lose this as otherwise each
     990             :            tdb_wipe_all() in a transaction will increase the size of
     991             :            the tdb by the size of the recovery area */
     992         165 :         if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
     993           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery head\n"));
     994           0 :                 goto failed;
     995             :         }
     996             : 
     997         165 :         if (recovery_head != 0) {
     998           5 :                 struct tdb_record rec;
     999         152 :                 if (tdb->methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
    1000           0 :                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery record\n"));
    1001           0 :                         return -1;
    1002             :                 }
    1003         152 :                 recovery_size = rec.rec_len + sizeof(rec);
    1004             :         }
    1005             : 
    1006             :         /* wipe the hashes */
    1007      199901 :         for (i=0;i<tdb->hash_size;i++) {
    1008      199736 :                 if (tdb_ofs_write(tdb, TDB_HASH_TOP(i), &offset) == -1) {
    1009           0 :                         TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write hash %d\n", i));
    1010           0 :                         goto failed;
    1011             :                 }
    1012             :         }
    1013             : 
    1014             :         /* wipe the freelist */
    1015         165 :         if (tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
    1016           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write freelist\n"));
    1017           0 :                 goto failed;
    1018             :         }
    1019             : 
    1020             :         /* add all the rest of the file to the freelist, possibly leaving a gap
    1021             :            for the recovery area */
    1022         165 :         if (recovery_size == 0) {
    1023             :                 /* the simple case - the whole file can be used as a freelist */
    1024          13 :                 data_len = (tdb->map_size - TDB_DATA_START(tdb->hash_size));
    1025          13 :                 if (tdb_free_region(tdb, TDB_DATA_START(tdb->hash_size), data_len) != 0) {
    1026           0 :                         goto failed;
    1027             :                 }
    1028             :         } else {
    1029             :                 /* we need to add two freelist entries - one on either
    1030             :                    side of the recovery area
    1031             : 
    1032             :                    Note that we cannot shift the recovery area during
    1033             :                    this operation. Only the transaction.c code may
    1034             :                    move the recovery area or we risk subtle data
    1035             :                    corruption
    1036             :                 */
    1037         152 :                 data_len = (recovery_head - TDB_DATA_START(tdb->hash_size));
    1038         152 :                 if (tdb_free_region(tdb, TDB_DATA_START(tdb->hash_size), data_len) != 0) {
    1039           0 :                         goto failed;
    1040             :                 }
    1041             :                 /* and the 2nd free list entry after the recovery area - if any */
    1042         152 :                 data_len = tdb->map_size - (recovery_head+recovery_size);
    1043         152 :                 if (tdb_free_region(tdb, recovery_head+recovery_size, data_len) != 0) {
    1044           0 :                         goto failed;
    1045             :                 }
    1046             :         }
    1047             : 
    1048         165 :         tdb_increment_seqnum_nonblock(tdb);
    1049             : 
    1050         165 :         if (tdb_unlockall(tdb) != 0) {
    1051           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to unlock\n"));
    1052           0 :                 goto failed;
    1053             :         }
    1054             : 
    1055         153 :         return 0;
    1056             : 
    1057           0 : failed:
    1058           0 :         tdb_unlockall(tdb);
    1059           0 :         return -1;
    1060             : }
    1061             : 
    1062             : struct traverse_state {
    1063             :         bool error;
    1064             :         struct tdb_context *dest_db;
    1065             : };
    1066             : 
    1067             : /*
    1068             :   traverse function for repacking
    1069             :  */
    1070      155206 : static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data)
    1071             : {
    1072      155206 :         struct traverse_state *state = (struct traverse_state *)private_data;
    1073      155206 :         if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) {
    1074           0 :                 state->error = true;
    1075           0 :                 return -1;
    1076             :         }
    1077      104706 :         return 0;
    1078             : }
    1079             : 
    1080             : /*
    1081             :   repack a tdb
    1082             :  */
    1083         116 : _PUBLIC_ int tdb_repack(struct tdb_context *tdb)
    1084             : {
    1085           7 :         struct tdb_context *tmp_db;
    1086           7 :         struct traverse_state state;
    1087             : 
    1088           7 :         tdb_trace(tdb, "tdb_repack");
    1089             : 
    1090         116 :         if (tdb_transaction_start(tdb) != 0) {
    1091           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to start transaction\n"));
    1092           0 :                 return -1;
    1093             :         }
    1094             : 
    1095         116 :         tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb), TDB_INTERNAL, O_RDWR|O_CREAT, 0);
    1096         116 :         if (tmp_db == NULL) {
    1097           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to create tmp_db\n"));
    1098           0 :                 tdb_transaction_cancel(tdb);
    1099           0 :                 return -1;
    1100             :         }
    1101             : 
    1102         116 :         state.error = false;
    1103         116 :         state.dest_db = tmp_db;
    1104             : 
    1105         116 :         if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) {
    1106           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying out\n"));
    1107           0 :                 tdb_transaction_cancel(tdb);
    1108           0 :                 tdb_close(tmp_db);
    1109           0 :                 return -1;
    1110             :         }
    1111             : 
    1112         116 :         if (state.error) {
    1113           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during traversal\n"));
    1114           0 :                 tdb_transaction_cancel(tdb);
    1115           0 :                 tdb_close(tmp_db);
    1116           0 :                 return -1;
    1117             :         }
    1118             : 
    1119         116 :         if (tdb_wipe_all(tdb) != 0) {
    1120           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to wipe database\n"));
    1121           0 :                 tdb_transaction_cancel(tdb);
    1122           0 :                 tdb_close(tmp_db);
    1123           0 :                 return -1;
    1124             :         }
    1125             : 
    1126         116 :         state.error = false;
    1127         116 :         state.dest_db = tdb;
    1128             : 
    1129         116 :         if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) {
    1130           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying back\n"));
    1131           0 :                 tdb_transaction_cancel(tdb);
    1132           0 :                 tdb_close(tmp_db);
    1133           0 :                 return -1;
    1134             :         }
    1135             : 
    1136         116 :         if (state.error) {
    1137           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during second traversal\n"));
    1138           0 :                 tdb_transaction_cancel(tdb);
    1139           0 :                 tdb_close(tmp_db);
    1140           0 :                 return -1;
    1141             :         }
    1142             : 
    1143         116 :         tdb_close(tmp_db);
    1144             : 
    1145         116 :         if (tdb_transaction_commit(tdb) != 0) {
    1146           0 :                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to commit\n"));
    1147           0 :                 return -1;
    1148             :         }
    1149             : 
    1150         109 :         return 0;
    1151             : }
    1152             : 
    1153             : /* Even on files, we can get partial writes due to signals. */
    1154      766882 : bool tdb_write_all(int fd, const void *buf, size_t count)
    1155             : {
    1156     1533764 :         while (count) {
    1157       19453 :                 ssize_t ret;
    1158      766882 :                 ret = write(fd, buf, count);
    1159      766882 :                 if (ret < 0)
    1160           0 :                         return false;
    1161      766882 :                 buf = (const char *)buf + ret;
    1162      766882 :                 count -= ret;
    1163             :         }
    1164      747429 :         return true;
    1165             : }
    1166             : 
    1167    25011843 : bool tdb_add_off_t(tdb_off_t a, tdb_off_t b, tdb_off_t *pret)
    1168             : {
    1169    25011843 :         tdb_off_t ret = a + b;
    1170             : 
    1171    25011843 :         if ((ret < a) || (ret < b)) {
    1172           0 :                 return false;
    1173             :         }
    1174    25011843 :         *pret = ret;
    1175    25011843 :         return true;
    1176             : }
    1177             : 
    1178             : #ifdef TDB_TRACE
    1179             : static void tdb_trace_write(struct tdb_context *tdb, const char *str)
    1180             : {
    1181             :         if (!tdb_write_all(tdb->tracefd, str, strlen(str))) {
    1182             :                 close(tdb->tracefd);
    1183             :                 tdb->tracefd = -1;
    1184             :         }
    1185             : }
    1186             : 
    1187             : static void tdb_trace_start(struct tdb_context *tdb)
    1188             : {
    1189             :         tdb_off_t seqnum=0;
    1190             :         char msg[sizeof(tdb_off_t) * 4 + 1];
    1191             : 
    1192             :         tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
    1193             :         snprintf(msg, sizeof(msg), "%u ", seqnum);
    1194             :         tdb_trace_write(tdb, msg);
    1195             : }
    1196             : 
    1197             : static void tdb_trace_end(struct tdb_context *tdb)
    1198             : {
    1199             :         tdb_trace_write(tdb, "\n");
    1200             : }
    1201             : 
    1202             : static void tdb_trace_end_ret(struct tdb_context *tdb, int ret)
    1203             : {
    1204             :         char msg[sizeof(ret) * 4 + 4];
    1205             :         snprintf(msg, sizeof(msg), " = %i\n", ret);
    1206             :         tdb_trace_write(tdb, msg);
    1207             : }
    1208             : 
    1209             : static void tdb_trace_record(struct tdb_context *tdb, TDB_DATA rec)
    1210             : {
    1211             :         char msg[20 + rec.dsize*2], *p;
    1212             :         unsigned int i;
    1213             : 
    1214             :         /* We differentiate zero-length records from non-existent ones. */
    1215             :         if (rec.dptr == NULL) {
    1216             :                 tdb_trace_write(tdb, " NULL");
    1217             :                 return;
    1218             :         }
    1219             : 
    1220             :         /* snprintf here is purely cargo-cult programming. */
    1221             :         p = msg;
    1222             :         p += snprintf(p, sizeof(msg), " %zu:", rec.dsize);
    1223             :         for (i = 0; i < rec.dsize; i++)
    1224             :                 p += snprintf(p, 2, "%02x", rec.dptr[i]);
    1225             : 
    1226             :         tdb_trace_write(tdb, msg);
    1227             : }
    1228             : 
    1229             : void tdb_trace(struct tdb_context *tdb, const char *op)
    1230             : {
    1231             :         tdb_trace_start(tdb);
    1232             :         tdb_trace_write(tdb, op);
    1233             :         tdb_trace_end(tdb);
    1234             : }
    1235             : 
    1236             : void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op)
    1237             : {
    1238             :         char msg[sizeof(tdb_off_t) * 4 + 1];
    1239             : 
    1240             :         snprintf(msg, sizeof(msg), "%u ", seqnum);
    1241             :         tdb_trace_write(tdb, msg);
    1242             :         tdb_trace_write(tdb, op);
    1243             :         tdb_trace_end(tdb);
    1244             : }
    1245             : 
    1246             : void tdb_trace_open(struct tdb_context *tdb, const char *op,
    1247             :                     unsigned hash_size, unsigned tdb_flags, unsigned open_flags)
    1248             : {
    1249             :         char msg[128];
    1250             : 
    1251             :         snprintf(msg, sizeof(msg),
    1252             :                  "%s %u 0x%x 0x%x", op, hash_size, tdb_flags, open_flags);
    1253             :         tdb_trace_start(tdb);
    1254             :         tdb_trace_write(tdb, msg);
    1255             :         tdb_trace_end(tdb);
    1256             : }
    1257             : 
    1258             : void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret)
    1259             : {
    1260             :         tdb_trace_start(tdb);
    1261             :         tdb_trace_write(tdb, op);
    1262             :         tdb_trace_end_ret(tdb, ret);
    1263             : }
    1264             : 
    1265             : void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret)
    1266             : {
    1267             :         tdb_trace_start(tdb);
    1268             :         tdb_trace_write(tdb, op);
    1269             :         tdb_trace_write(tdb, " =");
    1270             :         tdb_trace_record(tdb, ret);
    1271             :         tdb_trace_end(tdb);
    1272             : }
    1273             : 
    1274             : void tdb_trace_1rec(struct tdb_context *tdb, const char *op,
    1275             :                     TDB_DATA rec)
    1276             : {
    1277             :         tdb_trace_start(tdb);
    1278             :         tdb_trace_write(tdb, op);
    1279             :         tdb_trace_record(tdb, rec);
    1280             :         tdb_trace_end(tdb);
    1281             : }
    1282             : 
    1283             : void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op,
    1284             :                         TDB_DATA rec, int ret)
    1285             : {
    1286             :         tdb_trace_start(tdb);
    1287             :         tdb_trace_write(tdb, op);
    1288             :         tdb_trace_record(tdb, rec);
    1289             :         tdb_trace_end_ret(tdb, ret);
    1290             : }
    1291             : 
    1292             : void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op,
    1293             :                            TDB_DATA rec, TDB_DATA ret)
    1294             : {
    1295             :         tdb_trace_start(tdb);
    1296             :         tdb_trace_write(tdb, op);
    1297             :         tdb_trace_record(tdb, rec);
    1298             :         tdb_trace_write(tdb, " =");
    1299             :         tdb_trace_record(tdb, ret);
    1300             :         tdb_trace_end(tdb);
    1301             : }
    1302             : 
    1303             : void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
    1304             :                              TDB_DATA rec1, TDB_DATA rec2, unsigned flag,
    1305             :                              int ret)
    1306             : {
    1307             :         char msg[1 + sizeof(ret) * 4];
    1308             : 
    1309             :         snprintf(msg, sizeof(msg), " %#x", flag);
    1310             :         tdb_trace_start(tdb);
    1311             :         tdb_trace_write(tdb, op);
    1312             :         tdb_trace_record(tdb, rec1);
    1313             :         tdb_trace_record(tdb, rec2);
    1314             :         tdb_trace_write(tdb, msg);
    1315             :         tdb_trace_end_ret(tdb, ret);
    1316             : }
    1317             : 
    1318             : void tdb_trace_1plusn_rec_flag_ret(struct tdb_context *tdb, const char *op,
    1319             :                                    TDB_DATA rec,
    1320             :                                    const TDB_DATA *recs, int num_recs,
    1321             :                                    unsigned flag, int ret)
    1322             : {
    1323             :         char msg[1 + sizeof(ret) * 4];
    1324             :         int i;
    1325             : 
    1326             :         snprintf(msg, sizeof(msg), " %#x", flag);
    1327             :         tdb_trace_start(tdb);
    1328             :         tdb_trace_write(tdb, op);
    1329             :         tdb_trace_record(tdb, rec);
    1330             :         for (i=0; i<num_recs; i++) {
    1331             :                 tdb_trace_record(tdb, recs[i]);
    1332             :         }
    1333             :         tdb_trace_write(tdb, msg);
    1334             :         tdb_trace_end_ret(tdb, ret);
    1335             : }
    1336             : 
    1337             : void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
    1338             :                            TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret)
    1339             : {
    1340             :         tdb_trace_start(tdb);
    1341             :         tdb_trace_write(tdb, op);
    1342             :         tdb_trace_record(tdb, rec1);
    1343             :         tdb_trace_record(tdb, rec2);
    1344             :         tdb_trace_write(tdb, " =");
    1345             :         tdb_trace_record(tdb, ret);
    1346             :         tdb_trace_end(tdb);
    1347             : }
    1348             : #endif

Generated by: LCOV version 1.14