LCOV - code coverage report
Current view: top level - lib/tdb/common - tdb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 439 554 79.2 %
Date: 2024-02-28 12:06:22 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    22440122 : _PUBLIC_ void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)
      37             : {
      38    22440122 :         tdb_off_t seqnum=0;
      39             : 
      40    22440122 :         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    22439969 :         tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
      48    22439969 :         seqnum++;
      49    22439969 :         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    96911174 : static void tdb_increment_seqnum(struct tdb_context *tdb)
      57             : {
      58    96911174 :         if (!(tdb->flags & TDB_SEQNUM)) {
      59    69943457 :                 return;
      60             :         }
      61             : 
      62    24170570 :         if (tdb->transaction != NULL) {
      63    22439955 :                 tdb_increment_seqnum_nonblock(tdb);
      64    22439955 :                 return;
      65             :         }
      66             : 
      67             : #if defined(HAVE___ATOMIC_ADD_FETCH) && defined(HAVE___ATOMIC_ADD_LOAD)
      68     1730615 :         if (tdb->map_ptr != NULL) {
      69     1730615 :                 uint32_t *pseqnum = (uint32_t *)(
      70     1727190 :                         TDB_SEQNUM_OFS + (char *)tdb->map_ptr);
      71     1730615 :                 __atomic_add_fetch(pseqnum, 1, __ATOMIC_SEQ_CST);
      72     1730615 :                 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   499365353 : static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
      87             : {
      88   499365353 :         return memcmp(data.dptr, key.dptr, data.dsize);
      89             : }
      90             : 
      91  1009495462 : void tdb_chainwalk_init(struct tdb_chainwalk_ctx *ctx, tdb_off_t ptr)
      92             : {
      93  1009495462 :         *ctx = (struct tdb_chainwalk_ctx) { .slow_ptr = ptr };
      94  1005952866 : }
      95             : 
      96  2754107171 : bool tdb_chainwalk_check(struct tdb_context *tdb,
      97             :                          struct tdb_chainwalk_ctx *ctx,
      98             :                          tdb_off_t next_ptr)
      99             : {
     100   276786664 :         int ret;
     101             : 
     102  2754107171 :         if (ctx->slow_chase) {
     103  1259354107 :                 ret = tdb_ofs_read(tdb, ctx->slow_ptr, &ctx->slow_ptr);
     104  1259354107 :                 if (ret == -1) {
     105           0 :                         return false;
     106             :                 }
     107             :         }
     108  2754107171 :         ctx->slow_chase = !ctx->slow_chase;
     109             : 
     110  2754107171 :         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  2477320505 :         return true;
     118             : }
     119             : 
     120             : /* Returns 0 on fail.  On success, return offset of record, and fills
     121             :    in rec */
     122   845530408 : static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
     123             :                         struct tdb_record *r)
     124             : {
     125    27948190 :         tdb_off_t rec_ptr;
     126    27948190 :         struct tdb_chainwalk_ctx chainwalk;
     127             : 
     128             :         /* read in the hash top */
     129   845530408 :         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
     130           0 :                 return 0;
     131             : 
     132   845530408 :         tdb_chainwalk_init(&chainwalk, rec_ptr);
     133             : 
     134             :         /* keep looking until we find the right record */
     135  2931546512 :         while (rec_ptr) {
     136   217917121 :                 bool ok;
     137             : 
     138  2559640400 :                 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
     139           0 :                         return 0;
     140             : 
     141  2559640400 :                 if (!TDB_DEAD(r) && hash==r->full_hash
     142   499365611 :                     && key.dsize==r->key_len
     143   499365353 :                     && tdb_parse_data(tdb, key, rec_ptr + sizeof(*r),
     144             :                                       r->key_len, tdb_key_compare,
     145             :                                       NULL) == 0) {
     146   473624295 :                         return rec_ptr;
     147             :                 }
     148  2086016105 :                 rec_ptr = r->next;
     149             : 
     150  2086016105 :                 ok = tdb_chainwalk_check(tdb, &chainwalk, rec_ptr);
     151  2086016105 :                 if (!ok) {
     152           1 :                         return 0;
     153             :                 }
     154             :         }
     155   371906112 :         tdb->ecode = TDB_ERR_NOEXIST;
     156   371906112 :         return 0;
     157             : }
     158             : 
     159             : /* As tdb_find, but if you succeed, keep the lock */
     160   780245036 : 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    26251205 :         uint32_t rec_ptr;
     164             : 
     165   780245036 :         if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
     166           0 :                 return 0;
     167   780245036 :         if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
     168   321912481 :                 tdb_unlock(tdb, BUCKET(hash), locktype);
     169   753993831 :         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     7356986 : static int tdb_update_hash_cmp(TDB_DATA key, TDB_DATA data, void *private_data)
     181             : {
     182     7356986 :         struct tdb_update_hash_state *state = private_data;
     183     7356986 :         unsigned char *dptr = data.dptr;
     184      312462 :         int i;
     185             : 
     186     7356986 :         if (state->dbufs_len != data.dsize) {
     187           0 :                 return -1;
     188             :         }
     189             : 
     190    10284728 :         for (i=0; i<state->num_dbufs; i++) {
     191     8140517 :                 TDB_DATA dbuf = state->dbufs[i];
     192     8140517 :                 if( dbuf.dsize > 0) {
     193      318592 :                         int ret;
     194     8140098 :                         ret = memcmp(dptr, dbuf.dptr, dbuf.dsize);
     195     8140098 :                         if (ret != 0) {
     196     5315609 :                                 return -1;
     197             :                         }
     198     2927323 :                         dptr += dbuf.dsize;
     199             :                 }
     200             :         }
     201             : 
     202     2041377 :         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    65285372 : 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     1696985 :         struct tdb_record rec;
     215     1696985 :         tdb_off_t rec_ptr, ofs;
     216     1696985 :         int i;
     217             : 
     218             :         /* find entry */
     219    65285372 :         if (!(rec_ptr = tdb_find(tdb, key, hash, &rec)))
     220    49239204 :                 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    15291740 :         if (rec.data_len == dbufs_len) {
     225     7356986 :                 struct tdb_update_hash_state state = {
     226             :                         .dbufs = dbufs, .num_dbufs = num_dbufs,
     227             :                         .dbufs_len = dbufs_len
     228             :                 };
     229      312462 :                 int ret;
     230             : 
     231     7356986 :                 ret = tdb_parse_record(tdb, key, tdb_update_hash_cmp, &state);
     232     7356986 :                 if (ret == 0) {
     233     2144211 :                         return 0;
     234             :                 }
     235             :         }
     236             : 
     237             :         /* must be long enough key, data and tailer */
     238    13147529 :         if (rec.rec_len < key.dsize + dbufs_len + sizeof(tdb_off_t)) {
     239     1441903 :                 tdb->ecode = TDB_SUCCESS; /* Not really an error */
     240     1441903 :                 return -1;
     241             :         }
     242             : 
     243    11705626 :         ofs = rec_ptr + sizeof(rec) + rec.key_len;
     244             : 
     245    28425035 :         for (i=0; i<num_dbufs; i++) {
     246    16719409 :                 TDB_DATA dbuf = dbufs[i];
     247      820143 :                 int ret;
     248             : 
     249    16719409 :                 ret = tdb->methods->tdb_write(tdb, ofs, dbuf.dptr, dbuf.dsize);
     250    16719409 :                 if (ret == -1) {
     251     1696985 :                         return -1;
     252             :                 }
     253    16719409 :                 ofs += dbuf.dsize;
     254             :         }
     255             : 
     256    11705626 :         if (dbufs_len != rec.data_len) {
     257             :                 /* update size */
     258     6492851 :                 rec.data_len = dbufs_len;
     259     6492851 :                 return tdb_rec_write(tdb, rec_ptr, &rec);
     260             :         }
     261             : 
     262     5003147 :         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   150595112 : static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
     272             : {
     273    12624699 :         tdb_off_t rec_ptr;
     274    12624699 :         struct tdb_record rec;
     275    12624699 :         TDB_DATA ret;
     276    12624699 :         uint32_t hash;
     277             : 
     278             :         /* find which hash bucket it is in */
     279   150595112 :         hash = tdb->hash_fn(&key);
     280   150595112 :         if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec)))
     281    96999761 :                 return tdb_null;
     282             : 
     283    53595351 :         ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
     284             :                                   rec.data_len);
     285    53595351 :         ret.dsize = rec.data_len;
     286    53595351 :         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
     287    53595351 :         return ret;
     288             : }
     289             : 
     290   150526177 : _PUBLIC_ TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
     291             : {
     292   150526177 :         TDB_DATA ret = _tdb_fetch(tdb, key);
     293             : 
     294    12624401 :         tdb_trace_1rec_retrec(tdb, "tdb_fetch", key, ret);
     295   150526177 :         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   547614045 : _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    10102911 :         tdb_off_t rec_ptr;
     322    10102911 :         struct tdb_record rec;
     323    10102911 :         int ret;
     324    10102911 :         uint32_t hash;
     325             : 
     326             :         /* find which hash bucket it is in */
     327   547614045 :         hash = tdb->hash_fn(&key);
     328             : 
     329   547614045 :         if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
     330             :                 /* record not found */
     331     2034845 :                 tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1);
     332   147098062 :                 tdb->ecode = TDB_ERR_NOEXIST;
     333   147098062 :                 return -1;
     334             :         }
     335     8068066 :         tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0);
     336             : 
     337   400515983 :         ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
     338             :                              rec.data_len, parser, private_data);
     339             : 
     340   400515983 :         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
     341             : 
     342   400515983 :         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    27519852 : static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
     352             : {
     353     2581328 :         struct tdb_record rec;
     354             : 
     355    27519852 :         if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
     356    24918620 :                 return 0;
     357       20050 :         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
     358       20050 :         return 1;
     359             : }
     360             : 
     361       78556 : _PUBLIC_ int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
     362             : {
     363       78556 :         uint32_t hash = tdb->hash_fn(&key);
     364        2598 :         int ret;
     365             : 
     366       78556 :         ret = tdb_exists_hash(tdb, key, hash);
     367        2598 :         tdb_trace_1rec_ret(tdb, "tdb_exists", key, ret);
     368       78556 :         return ret;
     369             : }
     370             : 
     371             : /*
     372             :  * Move a dead record to the freelist. The hash chain and freelist
     373             :  * must be locked.
     374             :  */
     375     3134348 : 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      208633 :         int ret;
     382             : 
     383     3134348 :         ret = tdb_write_lock_record(tdb, rec_ptr);
     384     3134348 :         if (ret == -1) {
     385             :                 /* Someone traversing here: Just leave it dead */
     386       51695 :                 return 0;
     387             :         }
     388     3047641 :         ret = tdb_write_unlock_record(tdb, rec_ptr);
     389     3047641 :         if (ret == -1) {
     390           0 :                 return -1;
     391             :         }
     392     3047641 :         ret = tdb_ofs_write(tdb, last_ptr, &rec->next);
     393     3047641 :         if (ret == -1) {
     394           0 :                 return -1;
     395             :         }
     396             : 
     397     3047641 :         *deleted = true;
     398             : 
     399     3047641 :         ret = tdb_free(tdb, rec_ptr, rec);
     400     3047641 :         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    82272670 : int tdb_trim_dead(struct tdb_context *tdb, uint32_t hash)
     408             : {
     409     3542596 :         struct tdb_chainwalk_ctx chainwalk;
     410     3542596 :         struct tdb_record rec;
     411     3542596 :         tdb_off_t last_ptr, rec_ptr;
     412    82272670 :         bool locked_freelist = false;
     413    82272670 :         int num_dead = 0;
     414     3542596 :         int ret;
     415             : 
     416    82272670 :         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    82272670 :         tdb_chainwalk_init(&chainwalk, last_ptr);
     424             : 
     425    82272670 :         ret = tdb_ofs_read(tdb, last_ptr, &rec_ptr);
     426    82272670 :         if (ret == -1) {
     427           0 :                 return -1;
     428             :         }
     429             : 
     430   354658165 :         while (rec_ptr != 0) {
     431   272385495 :                 bool deleted = false;
     432    38643688 :                 uint32_t next;
     433             : 
     434   272385495 :                 ret = tdb_rec_read(tdb, rec_ptr, &rec);
     435   272385495 :                 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   272385495 :                 next = rec.next;
     446             : 
     447   272385495 :                 if (rec.magic == TDB_DEAD_MAGIC) {
     448     4674081 :                         num_dead += 1;
     449             : 
     450     4674081 :                         if (num_dead > tdb->max_dead_records) {
     451             : 
     452     3134348 :                                 if (!locked_freelist) {
     453             :                                         /*
     454             :                                          * Lock the freelist only if
     455             :                                          * it's really required.
     456             :                                          */
     457     3063317 :                                         ret = tdb_lock(tdb, -1, F_WRLCK);
     458     3063317 :                                         if (ret == -1) {
     459           0 :                                                 goto fail;
     460             :                                         };
     461     2884167 :                                         locked_freelist = true;
     462             :                                 }
     463             : 
     464     3134348 :                                 ret = tdb_del_dead(
     465             :                                         tdb,
     466             :                                         last_ptr,
     467             :                                         rec_ptr,
     468             :                                         &rec,
     469             :                                         &deleted);
     470             : 
     471     3134348 :                                 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   272385495 :                 if (!deleted) {
     486    38470067 :                         bool ok;
     487             : 
     488   269337854 :                         last_ptr = rec_ptr;
     489             : 
     490   269337854 :                         ok = tdb_chainwalk_check(tdb, &chainwalk, next);
     491   269337854 :                         if (!ok) {
     492           0 :                                 ret = -1;
     493           0 :                                 goto fail;
     494             :                         }
     495             :                 }
     496   272385495 :                 rec_ptr = next;
     497             :         }
     498    78730074 :         ret = 0;
     499    82272670 : fail:
     500    82272670 :         if (locked_freelist) {
     501     3063317 :                 tdb_unlock(tdb, -1, F_WRLCK);
     502             :         }
     503    78730074 :         return ret;
     504             : }
     505             : 
     506             : /* delete an entry in the database given a key */
     507    54516026 : static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
     508             : {
     509      942267 :         tdb_off_t rec_ptr;
     510      942267 :         struct tdb_record rec;
     511      942267 :         int ret;
     512             : 
     513    54516026 :         if (tdb->read_only || tdb->traverse_read) {
     514           0 :                 tdb->ecode = TDB_ERR_RDONLY;
     515           0 :                 return -1;
     516             :         }
     517             : 
     518    54516026 :         rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK, &rec);
     519    54516026 :         if (rec_ptr == 0) {
     520    49551962 :                 return -1;
     521             :         }
     522             : 
     523             :         /*
     524             :          * Mark the record dead
     525             :          */
     526     4201170 :         rec.magic = TDB_DEAD_MAGIC;
     527     4201170 :         ret = tdb_rec_write(tdb, rec_ptr, &rec);
     528     4201170 :         if (ret == -1) {
     529           0 :                 goto done;
     530             :         }
     531             : 
     532     4201170 :         tdb_increment_seqnum(tdb);
     533             : 
     534     4201170 :         ret = tdb_trim_dead(tdb, hash);
     535     4201170 : done:
     536     4201170 :         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     4021797 :         return ret;
     539             : }
     540             : 
     541     3080702 : _PUBLIC_ int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
     542             : {
     543     3080702 :         uint32_t hash = tdb->hash_fn(&key);
     544      156627 :         int ret;
     545             : 
     546     3080702 :         ret = tdb_delete_hash(tdb, key, hash);
     547      156627 :         tdb_trace_1rec_ret(tdb, "tdb_delete", key, ret);
     548     3080702 :         return ret;
     549             : }
     550             : 
     551             : /*
     552             :  * See if we have a dead record around with enough space
     553             :  */
     554     1192674 : 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        5330 :         tdb_off_t rec_ptr, last_ptr;
     559        5330 :         struct tdb_chainwalk_ctx chainwalk;
     560     1192674 :         tdb_off_t best_rec_ptr = 0;
     561     1192674 :         tdb_off_t best_last_ptr = 0;
     562     1192674 :         struct tdb_record best = { .rec_len = UINT32_MAX };
     563             : 
     564     1192674 :         length += sizeof(tdb_off_t); /* tailer */
     565             : 
     566     1192674 :         last_ptr = TDB_HASH_TOP(hash);
     567             : 
     568             :         /* read in the hash top */
     569     1192674 :         if (tdb_ofs_read(tdb, last_ptr, &rec_ptr) == -1)
     570           0 :                 return 0;
     571             : 
     572     1192674 :         tdb_chainwalk_init(&chainwalk, rec_ptr);
     573             : 
     574             :         /* keep looking until we find the right record */
     575     2373600 :         while (rec_ptr) {
     576        1773 :                 bool ok;
     577             : 
     578     1180926 :                 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
     579           0 :                         return 0;
     580             : 
     581     1180926 :                 if (TDB_DEAD(r) && (r->rec_len >= length) &&
     582     1030409 :                     (r->rec_len < best.rec_len)) {
     583      794101 :                         best_rec_ptr = rec_ptr;
     584      794101 :                         best_last_ptr = last_ptr;
     585      794101 :                         best = *r;
     586             :                 }
     587     1180926 :                 last_ptr = rec_ptr;
     588     1180926 :                 rec_ptr = r->next;
     589             : 
     590     1180926 :                 ok = tdb_chainwalk_check(tdb, &chainwalk, rec_ptr);
     591     1180926 :                 if (!ok) {
     592           0 :                         return 0;
     593             :                 }
     594             :         }
     595             : 
     596     1192674 :         if (best.rec_len == UINT32_MAX) {
     597      399679 :                 return 0;
     598             :         }
     599             : 
     600      788668 :         *r = best;
     601      788668 :         *p_last_ptr = best_last_ptr;
     602      788668 :         return best_rec_ptr;
     603             : }
     604             : 
     605    92726668 : 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     4275715 :         struct tdb_record rec;
     610     4275715 :         tdb_off_t rec_ptr, ofs;
     611     4275715 :         tdb_len_t rec_len, dbufs_len;
     612     4275715 :         int i;
     613    92726668 :         int ret = -1;
     614             : 
     615    92726668 :         dbufs_len = 0;
     616             : 
     617   193921100 :         for (i=0; i<num_dbufs; i++) {
     618   101194432 :                 size_t dsize = dbufs[i].dsize;
     619             : 
     620   101194432 :                 if ((dsize != 0) && (dbufs[i].dptr == NULL)) {
     621           0 :                         tdb->ecode = TDB_ERR_EINVAL;
     622           0 :                         goto fail;
     623             :                 }
     624             : 
     625   101194432 :                 dbufs_len += dsize;
     626   101194432 :                 if (dbufs_len < dsize) {
     627           0 :                         tdb->ecode = TDB_ERR_OOM;
     628           0 :                         goto fail;
     629             :                 }
     630             :         }
     631             : 
     632    92726668 :         rec_len = key.dsize + dbufs_len;
     633    92726668 :         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    92726668 :         if (flag == TDB_INSERT) {
     640    27441296 :                 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    65285372 :                 if (tdb_update_hash(tdb, key, hash, dbufs, num_dbufs,
     647             :                                     dbufs_len) == 0) {
     648    13849837 :                         goto done;
     649             :                 }
     650    51435535 :                 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    78860168 :         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    78860168 :         if (flag != TDB_INSERT)
     664    51435324 :                 tdb_delete_hash(tdb, key, hash);
     665             : 
     666             :         /* we have to allocate some space */
     667    78860168 :         rec_ptr = tdb_allocate(tdb, hash, rec_len, &rec);
     668             : 
     669    78860168 :         if (rec_ptr == 0) {
     670           1 :                 goto fail;
     671             :         }
     672             : 
     673             :         /* Read hash top into next ptr */
     674    78860167 :         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
     675           0 :                 goto fail;
     676             : 
     677    78860167 :         rec.key_len = key.dsize;
     678    78860167 :         rec.data_len = dbufs_len;
     679    78860167 :         rec.full_hash = hash;
     680    78860167 :         rec.magic = TDB_MAGIC;
     681             : 
     682    78860167 :         ofs = rec_ptr;
     683             : 
     684             :         /* write out and point the top of the hash chain at it */
     685    78860167 :         ret = tdb_rec_write(tdb, ofs, &rec);
     686    78860167 :         if (ret == -1) {
     687           0 :                 goto fail;
     688             :         }
     689    78860167 :         ofs += sizeof(rec);
     690             : 
     691    78860167 :         ret = tdb->methods->tdb_write(tdb, ofs, key.dptr, key.dsize);
     692    78860167 :         if (ret == -1) {
     693           0 :                 goto fail;
     694             :         }
     695    78860167 :         ofs += key.dsize;
     696             : 
     697   161065866 :         for (i=0; i<num_dbufs; i++) {
     698    82205699 :                 if (dbufs[i].dsize == 0) {
     699      952777 :                         continue;
     700             :                 }
     701             : 
     702    81252922 :                 ret = tdb->methods->tdb_write(tdb, ofs, dbufs[i].dptr,
     703    77846247 :                                               dbufs[i].dsize);
     704    81252922 :                 if (ret == -1) {
     705           0 :                         goto fail;
     706             :                 }
     707    81252922 :                 ofs += dbufs[i].dsize;
     708             :         }
     709             : 
     710    78860167 :         ret = tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr);
     711    78860167 :         if (ret == -1) {
     712             :                 /* Need to tdb_unallocate() here */
     713           0 :                 goto fail;
     714             :         }
     715             : 
     716    78860167 :  done:
     717    92710004 :         ret = 0;
     718    88450953 :  fail:
     719    88451121 :         if (ret == 0) {
     720    92710004 :                 tdb_increment_seqnum(tdb);
     721             :         }
     722    92726668 :         return ret;
     723             : }
     724             : 
     725    84535266 : static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
     726             :                       TDB_DATA dbuf, int flag, uint32_t hash)
     727             : {
     728    84535266 :         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    84535377 : _PUBLIC_ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
     737             : {
     738     4129384 :         uint32_t hash;
     739     4129384 :         int ret;
     740             : 
     741    84535377 :         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    84535266 :         hash = tdb->hash_fn(&key);
     749    84535266 :         if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
     750           0 :                 return -1;
     751             : 
     752    84535266 :         ret = _tdb_store(tdb, key, dbuf, flag, hash);
     753     4129384 :         tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, ret);
     754    84535266 :         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
     755    84535266 :         return ret;
     756             : }
     757             : 
     758     8122467 : _PUBLIC_ int tdb_storev(struct tdb_context *tdb, TDB_DATA key,
     759             :                         const TDB_DATA *dbufs, int num_dbufs, int flag)
     760             : {
     761      146033 :         uint32_t hash;
     762      146033 :         int ret;
     763             : 
     764     8122467 :         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     8122467 :         hash = tdb->hash_fn(&key);
     773     8122467 :         if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
     774           0 :                 return -1;
     775             : 
     776     8122467 :         ret = _tdb_storev(tdb, key, dbufs, num_dbufs, flag, hash);
     777      146033 :         tdb_trace_1plusn_rec_flag_ret(tdb, "tdb_storev", key,
     778      146033 :                                       dbufs, num_dbufs, flag, -1);
     779     8122467 :         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
     780     8122467 :         return ret;
     781             : }
     782             : 
     783             : /* Append to an entry. Create if not exist. */
     784       68935 : _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       68935 :         int ret = -1;
     789             : 
     790             :         /* find which hash bucket it is in */
     791       68935 :         hash = tdb->hash_fn(&key);
     792       68935 :         if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
     793           0 :                 return -1;
     794             : 
     795       68935 :         dbufs[0] = _tdb_fetch(tdb, key);
     796       68935 :         dbufs[1] = new_dbuf;
     797             : 
     798       68935 :         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       68935 :         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
     802       68935 :         SAFE_FREE(dbufs[0].dptr);
     803       68637 :         return ret;
     804             : }
     805             : 
     806             : 
     807             : /*
     808             :   return the name of the current tdb file
     809             :   useful for external logging functions
     810             : */
     811     4435146 : _PUBLIC_ const char *tdb_name(struct tdb_context *tdb)
     812             : {
     813     4435146 :         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     1554736 : _PUBLIC_ int tdb_fd(struct tdb_context *tdb)
     822             : {
     823     1554736 :         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   197758278 : _PUBLIC_ int tdb_get_seqnum(struct tdb_context *tdb)
     847             : {
     848   197758278 :         tdb_off_t seqnum=0;
     849             : 
     850   197758278 :         if (tdb->transaction != NULL) {
     851    62769954 :                 tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
     852    62769954 :                 return seqnum;
     853             :         }
     854             : 
     855             : #if defined(HAVE___ATOMIC_ADD_FETCH) && defined(HAVE___ATOMIC_ADD_LOAD)
     856   134988324 :         if (tdb->map_ptr != NULL) {
     857   134988324 :                 uint32_t *pseqnum = (uint32_t *)(
     858   130101161 :                         TDB_SEQNUM_OFS + (char *)tdb->map_ptr);
     859     4887163 :                 uint32_t ret;
     860   134988324 :                 __atomic_load(pseqnum, &ret,__ATOMIC_SEQ_CST);
     861   134988324 :                 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      155378 : static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data)
    1071             : {
    1072      155378 :         struct traverse_state *state = (struct traverse_state *)private_data;
    1073      155378 :         if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) {
    1074           0 :                 state->error = true;
    1075           0 :                 return -1;
    1076             :         }
    1077      104878 :         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      861355 : bool tdb_write_all(int fd, const void *buf, size_t count)
    1155             : {
    1156     1722710 :         while (count) {
    1157       19453 :                 ssize_t ret;
    1158      861355 :                 ret = write(fd, buf, count);
    1159      861355 :                 if (ret < 0)
    1160           0 :                         return false;
    1161      861355 :                 buf = (const char *)buf + ret;
    1162      861355 :                 count -= ret;
    1163             :         }
    1164      841902 :         return true;
    1165             : }
    1166             : 
    1167    25047992 : bool tdb_add_off_t(tdb_off_t a, tdb_off_t b, tdb_off_t *pret)
    1168             : {
    1169    25047992 :         tdb_off_t ret = a + b;
    1170             : 
    1171    25047992 :         if ((ret < a) || (ret < b)) {
    1172           0 :                 return false;
    1173             :         }
    1174    25047992 :         *pret = ret;
    1175    25047992 :         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