LCOV - code coverage report
Current view: top level - lib/tdb/common - tdb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 439 554 79.2 %
Date: 2024-04-21 15:09:00 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    21795733 : _PUBLIC_ void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)
      37             : {
      38    21795733 :         tdb_off_t seqnum=0;
      39             : 
      40    21795733 :         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    21795580 :         tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
      48    21795580 :         seqnum++;
      49    21795580 :         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    88235400 : static void tdb_increment_seqnum(struct tdb_context *tdb)
      57             : {
      58    88235400 :         if (!(tdb->flags & TDB_SEQNUM)) {
      59    62007631 :                 return;
      60             :         }
      61             : 
      62    23420182 :         if (tdb->transaction != NULL) {
      63    21795566 :                 tdb_increment_seqnum_nonblock(tdb);
      64    21795566 :                 return;
      65             :         }
      66             : 
      67             : #if defined(HAVE___ATOMIC_ADD_FETCH) && defined(HAVE___ATOMIC_ADD_LOAD)
      68     1624616 :         if (tdb->map_ptr != NULL) {
      69     1624616 :                 uint32_t *pseqnum = (uint32_t *)(
      70     1621192 :                         TDB_SEQNUM_OFS + (char *)tdb->map_ptr);
      71     1624616 :                 __atomic_add_fetch(pseqnum, 1, __ATOMIC_SEQ_CST);
      72     1624616 :                 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   501223970 : static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
      87             : {
      88   501223970 :         return memcmp(data.dptr, key.dptr, data.dsize);
      89             : }
      90             : 
      91   954852230 : void tdb_chainwalk_init(struct tdb_chainwalk_ctx *ctx, tdb_off_t ptr)
      92             : {
      93   954852230 :         *ctx = (struct tdb_chainwalk_ctx) { .slow_ptr = ptr };
      94   951277040 : }
      95             : 
      96  2748991324 : bool tdb_chainwalk_check(struct tdb_context *tdb,
      97             :                          struct tdb_chainwalk_ctx *ctx,
      98             :                          tdb_off_t next_ptr)
      99             : {
     100   276859032 :         int ret;
     101             : 
     102  2748991324 :         if (ctx->slow_chase) {
     103  1257692170 :                 ret = tdb_ofs_read(tdb, ctx->slow_ptr, &ctx->slow_ptr);
     104  1257692170 :                 if (ret == -1) {
     105           0 :                         return false;
     106             :                 }
     107             :         }
     108  2748991324 :         ctx->slow_chase = !ctx->slow_chase;
     109             : 
     110  2748991324 :         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  2472132290 :         return true;
     118             : }
     119             : 
     120             : /* Returns 0 on fail.  On success, return offset of record, and fills
     121             :    in rec */
     122   807856901 : static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
     123             :                         struct tdb_record *r)
     124             : {
     125    27926741 :         tdb_off_t rec_ptr;
     126    27926741 :         struct tdb_chainwalk_ctx chainwalk;
     127             : 
     128             :         /* read in the hash top */
     129   807856901 :         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
     130           0 :                 return 0;
     131             : 
     132   807856901 :         tdb_chainwalk_init(&chainwalk, rec_ptr);
     133             : 
     134             :         /* keep looking until we find the right record */
     135  2901522052 :         while (rec_ptr) {
     136   217947711 :                 bool ok;
     137             : 
     138  2563710130 :                 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
     139           0 :                         return 0;
     140             : 
     141  2563710130 :                 if (!TDB_DEAD(r) && hash==r->full_hash
     142   501229107 :                     && key.dsize==r->key_len
     143   501223970 :                     && tdb_parse_data(tdb, key, rec_ptr + sizeof(*r),
     144             :                                       r->key_len, tdb_key_compare,
     145             :                                       NULL) == 0) {
     146   470044978 :                         return rec_ptr;
     147             :                 }
     148  2093665152 :                 rec_ptr = r->next;
     149             : 
     150  2093665152 :                 ok = tdb_chainwalk_check(tdb, &chainwalk, rec_ptr);
     151  2093665152 :                 if (!ok) {
     152           1 :                         return 0;
     153             :                 }
     154             :         }
     155   337811922 :         tdb->ecode = TDB_ERR_NOEXIST;
     156   337811922 :         return 0;
     157             : }
     158             : 
     159             : /* As tdb_find, but if you succeed, keep the lock */
     160   751011212 : 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    26212773 :         uint32_t rec_ptr;
     164             : 
     165   751011212 :         if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
     166           0 :                 return 0;
     167   751011212 :         if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
     168   296018079 :                 tdb_unlock(tdb, BUCKET(hash), locktype);
     169   724798439 :         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     7379888 : static int tdb_update_hash_cmp(TDB_DATA key, TDB_DATA data, void *private_data)
     181             : {
     182     7379888 :         struct tdb_update_hash_state *state = private_data;
     183     7379888 :         unsigned char *dptr = data.dptr;
     184      315280 :         int i;
     185             : 
     186     7379888 :         if (state->dbufs_len != data.dsize) {
     187           0 :                 return -1;
     188             :         }
     189             : 
     190    10229086 :         for (i=0; i<state->num_dbufs; i++) {
     191     8089753 :                 TDB_DATA dbuf = state->dbufs[i];
     192     8089753 :                 if( dbuf.dsize > 0) {
     193      321412 :                         int ret;
     194     8089391 :                         ret = memcmp(dptr, dbuf.dptr, dbuf.dsize);
     195     8089391 :                         if (ret != 0) {
     196     5343545 :                                 return -1;
     197             :                         }
     198     2848836 :                         dptr += dbuf.dsize;
     199             :                 }
     200             :         }
     201             : 
     202     2036343 :         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    56845689 : 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     1713968 :         struct tdb_record rec;
     215     1713968 :         tdb_off_t rec_ptr, ofs;
     216     1713968 :         int i;
     217             : 
     218             :         /* find entry */
     219    56845689 :         if (!(rec_ptr = tdb_find(tdb, key, hash, &rec)))
     220    41028443 :                 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    15051845 :         if (rec.data_len == dbufs_len) {
     225     7379888 :                 struct tdb_update_hash_state state = {
     226             :                         .dbufs = dbufs, .num_dbufs = num_dbufs,
     227             :                         .dbufs_len = dbufs_len
     228             :                 };
     229      315280 :                 int ret;
     230             : 
     231     7379888 :                 ret = tdb_parse_record(tdb, key, tdb_update_hash_cmp, &state);
     232     7379888 :                 if (ret == 0) {
     233     2139333 :                         return 0;
     234             :                 }
     235             :         }
     236             : 
     237             :         /* must be long enough key, data and tailer */
     238    12912512 :         if (rec.rec_len < key.dsize + dbufs_len + sizeof(tdb_off_t)) {
     239     1306403 :                 tdb->ecode = TDB_SUCCESS; /* Not really an error */
     240     1306403 :                 return -1;
     241             :         }
     242             : 
     243    11606109 :         ofs = rec_ptr + sizeof(rec) + rec.key_len;
     244             : 
     245    27945874 :         for (i=0; i<num_dbufs; i++) {
     246    16339765 :                 TDB_DATA dbuf = dbufs[i];
     247      824912 :                 int ret;
     248             : 
     249    16339765 :                 ret = tdb->methods->tdb_write(tdb, ofs, dbuf.dptr, dbuf.dsize);
     250    16339765 :                 if (ret == -1) {
     251     1713968 :                         return -1;
     252             :                 }
     253    16339765 :                 ofs += dbuf.dsize;
     254             :         }
     255             : 
     256    11606109 :         if (dbufs_len != rec.data_len) {
     257             :                 /* update size */
     258     6365554 :                 rec.data_len = dbufs_len;
     259     6365554 :                 return tdb_rec_write(tdb, rec_ptr, &rec);
     260             :         }
     261             : 
     262     5028265 :         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   150451239 : static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
     272             : {
     273    12614692 :         tdb_off_t rec_ptr;
     274    12614692 :         struct tdb_record rec;
     275    12614692 :         TDB_DATA ret;
     276    12614692 :         uint32_t hash;
     277             : 
     278             :         /* find which hash bucket it is in */
     279   150451239 :         hash = tdb->hash_fn(&key);
     280   150451239 :         if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec)))
     281    96517696 :                 return tdb_null;
     282             : 
     283    53933543 :         ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
     284             :                                   rec.data_len);
     285    53933543 :         ret.dsize = rec.data_len;
     286    53933543 :         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
     287    53933543 :         return ret;
     288             : }
     289             : 
     290   150381733 : _PUBLIC_ TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
     291             : {
     292   150381733 :         TDB_DATA ret = _tdb_fetch(tdb, key);
     293             : 
     294    12614394 :         tdb_trace_1rec_retrec(tdb, "tdb_fetch", key, ret);
     295   150381733 :         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   526966924 : _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    10042862 :         tdb_off_t rec_ptr;
     322    10042862 :         struct tdb_record rec;
     323    10042862 :         int ret;
     324    10042862 :         uint32_t hash;
     325             : 
     326             :         /* find which hash bucket it is in */
     327   526966924 :         hash = tdb->hash_fn(&key);
     328             : 
     329   526966924 :         if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
     330             :                 /* record not found */
     331     2024308 :                 tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1);
     332   129898490 :                 tdb->ecode = TDB_ERR_NOEXIST;
     333   129898490 :                 return -1;
     334             :         }
     335     8018554 :         tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0);
     336             : 
     337   397068434 :         ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
     338             :                              rec.data_len, parser, private_data);
     339             : 
     340   397068434 :         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
     341             : 
     342   397068434 :         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    27514856 : static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
     352             : {
     353     2595582 :         struct tdb_record rec;
     354             : 
     355    27514856 :         if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
     356    24899418 :                 return 0;
     357       20044 :         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
     358       20044 :         return 1;
     359             : }
     360             : 
     361       79593 : _PUBLIC_ int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
     362             : {
     363       79593 :         uint32_t hash = tdb->hash_fn(&key);
     364        2598 :         int ret;
     365             : 
     366       79593 :         ret = tdb_exists_hash(tdb, key, hash);
     367        2598 :         tdb_trace_1rec_ret(tdb, "tdb_exists", key, ret);
     368       79593 :         return ret;
     369             : }
     370             : 
     371             : /*
     372             :  * Move a dead record to the freelist. The hash chain and freelist
     373             :  * must be locked.
     374             :  */
     375     2989040 : 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      215275 :         int ret;
     382             : 
     383     2989040 :         ret = tdb_write_lock_record(tdb, rec_ptr);
     384     2989040 :         if (ret == -1) {
     385             :                 /* Someone traversing here: Just leave it dead */
     386       49410 :                 return 0;
     387             :         }
     388     2901271 :         ret = tdb_write_unlock_record(tdb, rec_ptr);
     389     2901271 :         if (ret == -1) {
     390           0 :                 return -1;
     391             :         }
     392     2901271 :         ret = tdb_ofs_write(tdb, last_ptr, &rec->next);
     393     2901271 :         if (ret == -1) {
     394           0 :                 return -1;
     395             :         }
     396             : 
     397     2901271 :         *deleted = true;
     398             : 
     399     2901271 :         ret = tdb_free(tdb, rec_ptr, rec);
     400     2901271 :         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    73761475 : int tdb_trim_dead(struct tdb_context *tdb, uint32_t hash)
     408             : {
     409     3575190 :         struct tdb_chainwalk_ctx chainwalk;
     410     3575190 :         struct tdb_record rec;
     411     3575190 :         tdb_off_t last_ptr, rec_ptr;
     412    73761475 :         bool locked_freelist = false;
     413    73761475 :         int num_dead = 0;
     414     3575190 :         int ret;
     415             : 
     416    73761475 :         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    73761475 :         tdb_chainwalk_init(&chainwalk, last_ptr);
     424             : 
     425    73761475 :         ret = tdb_ofs_read(tdb, last_ptr, &rec_ptr);
     426    73761475 :         if (ret == -1) {
     427           0 :                 return -1;
     428             :         }
     429             : 
     430   343346155 :         while (rec_ptr != 0) {
     431   269584680 :                 bool deleted = false;
     432    38651405 :                 uint32_t next;
     433             : 
     434   269584680 :                 ret = tdb_rec_read(tdb, rec_ptr, &rec);
     435   269584680 :                 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   269584680 :                 next = rec.next;
     446             : 
     447   269584680 :                 if (rec.magic == TDB_DEAD_MAGIC) {
     448     4440190 :                         num_dead += 1;
     449             : 
     450     4440190 :                         if (num_dead > tdb->max_dead_records) {
     451             : 
     452     2989040 :                                 if (!locked_freelist) {
     453             :                                         /*
     454             :                                          * Lock the freelist only if
     455             :                                          * it's really required.
     456             :                                          */
     457     2916880 :                                         ret = tdb_lock(tdb, -1, F_WRLCK);
     458     2916880 :                                         if (ret == -1) {
     459           0 :                                                 goto fail;
     460             :                                         };
     461     2731191 :                                         locked_freelist = true;
     462             :                                 }
     463             : 
     464     2989040 :                                 ret = tdb_del_dead(
     465             :                                         tdb,
     466             :                                         last_ptr,
     467             :                                         rec_ptr,
     468             :                                         &rec,
     469             :                                         &deleted);
     470             : 
     471     2989040 :                                 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   269584680 :                 if (!deleted) {
     486    38474489 :                         bool ok;
     487             : 
     488   266683409 :                         last_ptr = rec_ptr;
     489             : 
     490   266683409 :                         ok = tdb_chainwalk_check(tdb, &chainwalk, next);
     491   266683409 :                         if (!ok) {
     492           0 :                                 ret = -1;
     493           0 :                                 goto fail;
     494             :                         }
     495             :                 }
     496   269584680 :                 rec_ptr = next;
     497             :         }
     498    70186285 :         ret = 0;
     499    73761475 : fail:
     500    73761475 :         if (locked_freelist) {
     501     2916880 :                 tdb_unlock(tdb, -1, F_WRLCK);
     502             :         }
     503    70186285 :         return ret;
     504             : }
     505             : 
     506             : /* delete an entry in the database given a key */
     507    46078192 : static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
     508             : {
     509      959637 :         tdb_off_t rec_ptr;
     510      959637 :         struct tdb_record rec;
     511      959637 :         int ret;
     512             : 
     513    46078192 :         if (tdb->read_only || tdb->traverse_read) {
     514           0 :                 tdb->ecode = TDB_ERR_RDONLY;
     515           0 :                 return -1;
     516             :         }
     517             : 
     518    46078192 :         rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK, &rec);
     519    46078192 :         if (rec_ptr == 0) {
     520    41333172 :                 return -1;
     521             :         }
     522             : 
     523             :         /*
     524             :          * Mark the record dead
     525             :          */
     526     3971111 :         rec.magic = TDB_DEAD_MAGIC;
     527     3971111 :         ret = tdb_rec_write(tdb, rec_ptr, &rec);
     528     3971111 :         if (ret == -1) {
     529           0 :                 goto done;
     530             :         }
     531             : 
     532     3971111 :         tdb_increment_seqnum(tdb);
     533             : 
     534     3971111 :         ret = tdb_trim_dead(tdb, hash);
     535     3971111 : done:
     536     3971111 :         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     3785383 :         return ret;
     539             : }
     540             : 
     541     2978156 : _PUBLIC_ int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
     542             : {
     543     2978156 :         uint32_t hash = tdb->hash_fn(&key);
     544      161939 :         int ret;
     545             : 
     546     2978156 :         ret = tdb_delete_hash(tdb, key, hash);
     547      161939 :         tdb_trace_1rec_ret(tdb, "tdb_delete", key, ret);
     548     2978156 :         return ret;
     549             : }
     550             : 
     551             : /*
     552             :  * See if we have a dead record around with enough space
     553             :  */
     554     1106182 : 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        5332 :         tdb_off_t rec_ptr, last_ptr;
     559        5332 :         struct tdb_chainwalk_ctx chainwalk;
     560     1106182 :         tdb_off_t best_rec_ptr = 0;
     561     1106182 :         tdb_off_t best_last_ptr = 0;
     562     1106182 :         struct tdb_record best = { .rec_len = UINT32_MAX };
     563             : 
     564     1106182 :         length += sizeof(tdb_off_t); /* tailer */
     565             : 
     566     1106182 :         last_ptr = TDB_HASH_TOP(hash);
     567             : 
     568             :         /* read in the hash top */
     569     1106182 :         if (tdb_ofs_read(tdb, last_ptr, &rec_ptr) == -1)
     570           0 :                 return 0;
     571             : 
     572     1106182 :         tdb_chainwalk_init(&chainwalk, rec_ptr);
     573             : 
     574             :         /* keep looking until we find the right record */
     575     2221990 :         while (rec_ptr) {
     576        1803 :                 bool ok;
     577             : 
     578     1115808 :                 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
     579           0 :                         return 0;
     580             : 
     581     1115808 :                 if (TDB_DEAD(r) && (r->rec_len >= length) &&
     582      968525 :                     (r->rec_len < best.rec_len)) {
     583      733931 :                         best_rec_ptr = rec_ptr;
     584      733931 :                         best_last_ptr = last_ptr;
     585      733931 :                         best = *r;
     586             :                 }
     587     1115808 :                 last_ptr = rec_ptr;
     588     1115808 :                 rec_ptr = r->next;
     589             : 
     590     1115808 :                 ok = tdb_chainwalk_check(tdb, &chainwalk, rec_ptr);
     591     1115808 :                 if (!ok) {
     592           0 :                         return 0;
     593             :                 }
     594             :         }
     595             : 
     596     1106182 :         if (best.rec_len == UINT32_MAX) {
     597      373400 :                 return 0;
     598             :         }
     599             : 
     600      728484 :         *r = best;
     601      728484 :         *p_last_ptr = best_last_ptr;
     602      728484 :         return best_rec_ptr;
     603             : }
     604             : 
     605    84280952 : 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     4306952 :         struct tdb_record rec;
     610     4306952 :         tdb_off_t rec_ptr, ofs;
     611     4306952 :         tdb_len_t rec_len, dbufs_len;
     612     4306952 :         int i;
     613    84280952 :         int ret = -1;
     614             : 
     615    84280952 :         dbufs_len = 0;
     616             : 
     617   176420263 :         for (i=0; i<num_dbufs; i++) {
     618    92139311 :                 size_t dsize = dbufs[i].dsize;
     619             : 
     620    92139311 :                 if ((dsize != 0) && (dbufs[i].dptr == NULL)) {
     621           0 :                         tdb->ecode = TDB_ERR_EINVAL;
     622           0 :                         goto fail;
     623             :                 }
     624             : 
     625    92139311 :                 dbufs_len += dsize;
     626    92139311 :                 if (dbufs_len < dsize) {
     627           0 :                         tdb->ecode = TDB_ERR_OOM;
     628           0 :                         goto fail;
     629             :                 }
     630             :         }
     631             : 
     632    84280952 :         rec_len = key.dsize + dbufs_len;
     633    84280952 :         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    84280952 :         if (flag == TDB_INSERT) {
     640    27435263 :                 if (tdb_exists_hash(tdb, key, hash)) {
     641       16451 :                         tdb->ecode = TDB_ERR_EXISTS;
     642       16451 :                         goto fail;
     643             :                 }
     644             :         } else {
     645             :                 /* first try in-place update, on modify or replace. */
     646    56845689 :                 if (tdb_update_hash(tdb, key, hash, dbufs, num_dbufs,
     647             :                                     dbufs_len) == 0) {
     648    13745442 :                         goto done;
     649             :                 }
     650    43100247 :                 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    70518848 :         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    70518848 :         if (flag != TDB_INSERT)
     664    43100036 :                 tdb_delete_hash(tdb, key, hash);
     665             : 
     666             :         /* we have to allocate some space */
     667    70518848 :         rec_ptr = tdb_allocate(tdb, hash, rec_len, &rec);
     668             : 
     669    70518848 :         if (rec_ptr == 0) {
     670           1 :                 goto fail;
     671             :         }
     672             : 
     673             :         /* Read hash top into next ptr */
     674    70518847 :         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
     675           0 :                 goto fail;
     676             : 
     677    70518847 :         rec.key_len = key.dsize;
     678    70518847 :         rec.data_len = dbufs_len;
     679    70518847 :         rec.full_hash = hash;
     680    70518847 :         rec.magic = TDB_MAGIC;
     681             : 
     682    70518847 :         ofs = rec_ptr;
     683             : 
     684             :         /* write out and point the top of the hash chain at it */
     685    70518847 :         ret = tdb_rec_write(tdb, ofs, &rec);
     686    70518847 :         if (ret == -1) {
     687           0 :                 goto fail;
     688             :         }
     689    70518847 :         ofs += sizeof(rec);
     690             : 
     691    70518847 :         ret = tdb->methods->tdb_write(tdb, ofs, key.dptr, key.dsize);
     692    70518847 :         if (ret == -1) {
     693           0 :                 goto fail;
     694             :         }
     695    70518847 :         ofs += key.dsize;
     696             : 
     697   144077902 :         for (i=0; i<num_dbufs; i++) {
     698    73559055 :                 if (dbufs[i].dsize == 0) {
     699      890768 :                         continue;
     700             :                 }
     701             : 
     702    72668287 :                 ret = tdb->methods->tdb_write(tdb, ofs, dbufs[i].dptr,
     703    69235347 :                                               dbufs[i].dsize);
     704    72668287 :                 if (ret == -1) {
     705           0 :                         goto fail;
     706             :                 }
     707    72668287 :                 ofs += dbufs[i].dsize;
     708             :         }
     709             : 
     710    70518847 :         ret = tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr);
     711    70518847 :         if (ret == -1) {
     712             :                 /* Need to tdb_unallocate() here */
     713           0 :                 goto fail;
     714             :         }
     715             : 
     716    70518847 :  done:
     717    84264289 :         ret = 0;
     718    79974000 :  fail:
     719    79974210 :         if (ret == 0) {
     720    84264289 :                 tdb_increment_seqnum(tdb);
     721             :         }
     722    84280952 :         return ret;
     723             : }
     724             : 
     725    76666172 : static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
     726             :                       TDB_DATA dbuf, int flag, uint32_t hash)
     727             : {
     728    76666172 :         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    76666283 : _PUBLIC_ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
     737             : {
     738     4160876 :         uint32_t hash;
     739     4160876 :         int ret;
     740             : 
     741    76666283 :         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    76666172 :         hash = tdb->hash_fn(&key);
     749    76666172 :         if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
     750           0 :                 return -1;
     751             : 
     752    76666172 :         ret = _tdb_store(tdb, key, dbuf, flag, hash);
     753     4160876 :         tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, ret);
     754    76666172 :         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
     755    76666172 :         return ret;
     756             : }
     757             : 
     758     7545274 : _PUBLIC_ int tdb_storev(struct tdb_context *tdb, TDB_DATA key,
     759             :                         const TDB_DATA *dbufs, int num_dbufs, int flag)
     760             : {
     761      145778 :         uint32_t hash;
     762      145778 :         int ret;
     763             : 
     764     7545274 :         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     7545274 :         hash = tdb->hash_fn(&key);
     773     7545274 :         if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
     774           0 :                 return -1;
     775             : 
     776     7545274 :         ret = _tdb_storev(tdb, key, dbufs, num_dbufs, flag, hash);
     777      145778 :         tdb_trace_1plusn_rec_flag_ret(tdb, "tdb_storev", key,
     778      145778 :                                       dbufs, num_dbufs, flag, -1);
     779     7545274 :         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
     780     7545274 :         return ret;
     781             : }
     782             : 
     783             : /* Append to an entry. Create if not exist. */
     784       69506 : _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       69506 :         int ret = -1;
     789             : 
     790             :         /* find which hash bucket it is in */
     791       69506 :         hash = tdb->hash_fn(&key);
     792       69506 :         if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
     793           0 :                 return -1;
     794             : 
     795       69506 :         dbufs[0] = _tdb_fetch(tdb, key);
     796       69506 :         dbufs[1] = new_dbuf;
     797             : 
     798       69506 :         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       69506 :         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
     802       69506 :         SAFE_FREE(dbufs[0].dptr);
     803       69208 :         return ret;
     804             : }
     805             : 
     806             : 
     807             : /*
     808             :   return the name of the current tdb file
     809             :   useful for external logging functions
     810             : */
     811     4173257 : _PUBLIC_ const char *tdb_name(struct tdb_context *tdb)
     812             : {
     813     4173257 :         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     1622794 : _PUBLIC_ int tdb_fd(struct tdb_context *tdb)
     822             : {
     823     1622794 :         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   196540729 : _PUBLIC_ int tdb_get_seqnum(struct tdb_context *tdb)
     847             : {
     848   196540729 :         tdb_off_t seqnum=0;
     849             : 
     850   196540729 :         if (tdb->transaction != NULL) {
     851    60782295 :                 tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
     852    60782295 :                 return seqnum;
     853             :         }
     854             : 
     855             : #if defined(HAVE___ATOMIC_ADD_FETCH) && defined(HAVE___ATOMIC_ADD_LOAD)
     856   135758434 :         if (tdb->map_ptr != NULL) {
     857   135758434 :                 uint32_t *pseqnum = (uint32_t *)(
     858   130861139 :                         TDB_SEQNUM_OFS + (char *)tdb->map_ptr);
     859     4897295 :                 uint32_t ret;
     860   135758434 :                 __atomic_load(pseqnum, &ret,__ATOMIC_SEQ_CST);
     861   135758434 :                 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      155560 : static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data)
    1071             : {
    1072      155560 :         struct traverse_state *state = (struct traverse_state *)private_data;
    1073      155560 :         if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) {
    1074           0 :                 state->error = true;
    1075           0 :                 return -1;
    1076             :         }
    1077      105042 :         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      771933 : bool tdb_write_all(int fd, const void *buf, size_t count)
    1155             : {
    1156     1543866 :         while (count) {
    1157       20486 :                 ssize_t ret;
    1158      771933 :                 ret = write(fd, buf, count);
    1159      771933 :                 if (ret < 0)
    1160           0 :                         return false;
    1161      771933 :                 buf = (const char *)buf + ret;
    1162      771933 :                 count -= ret;
    1163             :         }
    1164      751447 :         return true;
    1165             : }
    1166             : 
    1167    24589029 : bool tdb_add_off_t(tdb_off_t a, tdb_off_t b, tdb_off_t *pret)
    1168             : {
    1169    24589029 :         tdb_off_t ret = a + b;
    1170             : 
    1171    24589029 :         if ((ret < a) || (ret < b)) {
    1172           0 :                 return false;
    1173             :         }
    1174    24589029 :         *pret = ret;
    1175    24589029 :         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