tdb: in tdb_delete_hash, make lock/unlock bracket more obvious
[samba.git] / lib / tdb / common / tdb.c
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 _PUBLIC_ void tdb_increment_seqnum_nonblock(struct tdb_context *tdb)
37 {
38         tdb_off_t seqnum=0;
39
40         if (!(tdb->flags & TDB_SEQNUM)) {
41                 return;
42         }
43
44         /* we ignore errors from this, as we have no sane way of
45            dealing with them.
46         */
47         tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
48         seqnum++;
49         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 static void tdb_increment_seqnum(struct tdb_context *tdb)
57 {
58         if (!(tdb->flags & TDB_SEQNUM)) {
59                 return;
60         }
61
62         if (tdb_nest_lock(tdb, TDB_SEQNUM_OFS, F_WRLCK,
63                           TDB_LOCK_WAIT|TDB_LOCK_PROBE) != 0) {
64                 return;
65         }
66
67         tdb_increment_seqnum_nonblock(tdb);
68
69         tdb_nest_unlock(tdb, TDB_SEQNUM_OFS, F_WRLCK, false);
70 }
71
72 static int tdb_key_compare(TDB_DATA key, TDB_DATA data, void *private_data)
73 {
74         return memcmp(data.dptr, key.dptr, data.dsize);
75 }
76
77 /* Returns 0 on fail.  On success, return offset of record, and fills
78    in rec */
79 static tdb_off_t tdb_find(struct tdb_context *tdb, TDB_DATA key, uint32_t hash,
80                         struct tdb_record *r)
81 {
82         tdb_off_t rec_ptr;
83
84         /* read in the hash top */
85         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
86                 return 0;
87
88         /* keep looking until we find the right record */
89         while (rec_ptr) {
90                 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
91                         return 0;
92
93                 if (!TDB_DEAD(r) && hash==r->full_hash
94                     && key.dsize==r->key_len
95                     && tdb_parse_data(tdb, key, rec_ptr + sizeof(*r),
96                                       r->key_len, tdb_key_compare,
97                                       NULL) == 0) {
98                         return rec_ptr;
99                 }
100                 /* detect tight infinite loop */
101                 if (rec_ptr == r->next) {
102                         tdb->ecode = TDB_ERR_CORRUPT;
103                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_find: loop detected.\n"));
104                         return 0;
105                 }
106                 rec_ptr = r->next;
107         }
108         tdb->ecode = TDB_ERR_NOEXIST;
109         return 0;
110 }
111
112 /* As tdb_find, but if you succeed, keep the lock */
113 tdb_off_t tdb_find_lock_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, int locktype,
114                            struct tdb_record *rec)
115 {
116         uint32_t rec_ptr;
117
118         if (tdb_lock(tdb, BUCKET(hash), locktype) == -1)
119                 return 0;
120         if (!(rec_ptr = tdb_find(tdb, key, hash, rec)))
121                 tdb_unlock(tdb, BUCKET(hash), locktype);
122         return rec_ptr;
123 }
124
125 static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
126
127 static int tdb_update_hash_cmp(TDB_DATA key, TDB_DATA data, void *private_data)
128 {
129         TDB_DATA *dbuf = (TDB_DATA *)private_data;
130
131         if (dbuf->dsize != data.dsize) {
132                 return -1;
133         }
134         if (memcmp(dbuf->dptr, data.dptr, data.dsize) != 0) {
135                 return -1;
136         }
137         return 0;
138 }
139
140 /* update an entry in place - this only works if the new data size
141    is <= the old data size and the key exists.
142    on failure return -1.
143 */
144 static int tdb_update_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash, TDB_DATA dbuf)
145 {
146         struct tdb_record rec;
147         tdb_off_t rec_ptr;
148
149         /* find entry */
150         if (!(rec_ptr = tdb_find(tdb, key, hash, &rec)))
151                 return -1;
152
153         /* it could be an exact duplicate of what is there - this is
154          * surprisingly common (eg. with a ldb re-index). */
155         if (rec.key_len == key.dsize &&
156             rec.data_len == dbuf.dsize &&
157             rec.full_hash == hash &&
158             tdb_parse_record(tdb, key, tdb_update_hash_cmp, &dbuf) == 0) {
159                 return 0;
160         }
161
162         /* must be long enough key, data and tailer */
163         if (rec.rec_len < key.dsize + dbuf.dsize + sizeof(tdb_off_t)) {
164                 tdb->ecode = TDB_SUCCESS; /* Not really an error */
165                 return -1;
166         }
167
168         if (tdb->methods->tdb_write(tdb, rec_ptr + sizeof(rec) + rec.key_len,
169                       dbuf.dptr, dbuf.dsize) == -1)
170                 return -1;
171
172         if (dbuf.dsize != rec.data_len) {
173                 /* update size */
174                 rec.data_len = dbuf.dsize;
175                 return tdb_rec_write(tdb, rec_ptr, &rec);
176         }
177
178         return 0;
179 }
180
181 /* find an entry in the database given a key */
182 /* If an entry doesn't exist tdb_err will be set to
183  * TDB_ERR_NOEXIST. If a key has no data attached
184  * then the TDB_DATA will have zero length but
185  * a non-zero pointer
186  */
187 static TDB_DATA _tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
188 {
189         tdb_off_t rec_ptr;
190         struct tdb_record rec;
191         TDB_DATA ret;
192         uint32_t hash;
193
194         /* find which hash bucket it is in */
195         hash = tdb->hash_fn(&key);
196         if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec)))
197                 return tdb_null;
198
199         ret.dptr = tdb_alloc_read(tdb, rec_ptr + sizeof(rec) + rec.key_len,
200                                   rec.data_len);
201         ret.dsize = rec.data_len;
202         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
203         return ret;
204 }
205
206 _PUBLIC_ TDB_DATA tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
207 {
208         TDB_DATA ret = _tdb_fetch(tdb, key);
209
210         tdb_trace_1rec_retrec(tdb, "tdb_fetch", key, ret);
211         return ret;
212 }
213
214 /*
215  * Find an entry in the database and hand the record's data to a parsing
216  * function. The parsing function is executed under the chain read lock, so it
217  * should be fast and should not block on other syscalls.
218  *
219  * DON'T CALL OTHER TDB CALLS FROM THE PARSER, THIS MIGHT LEAD TO SEGFAULTS.
220  *
221  * For mmapped tdb's that do not have a transaction open it points the parsing
222  * function directly at the mmap area, it avoids the malloc/memcpy in this
223  * case. If a transaction is open or no mmap is available, it has to do
224  * malloc/read/parse/free.
225  *
226  * This is interesting for all readers of potentially large data structures in
227  * the tdb records, ldb indexes being one example.
228  *
229  * Return -1 if the record was not found.
230  */
231
232 _PUBLIC_ int tdb_parse_record(struct tdb_context *tdb, TDB_DATA key,
233                      int (*parser)(TDB_DATA key, TDB_DATA data,
234                                    void *private_data),
235                      void *private_data)
236 {
237         tdb_off_t rec_ptr;
238         struct tdb_record rec;
239         int ret;
240         uint32_t hash;
241
242         /* find which hash bucket it is in */
243         hash = tdb->hash_fn(&key);
244
245         if (!(rec_ptr = tdb_find_lock_hash(tdb,key,hash,F_RDLCK,&rec))) {
246                 /* record not found */
247                 tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, -1);
248                 tdb->ecode = TDB_ERR_NOEXIST;
249                 return -1;
250         }
251         tdb_trace_1rec_ret(tdb, "tdb_parse_record", key, 0);
252
253         ret = tdb_parse_data(tdb, key, rec_ptr + sizeof(rec) + rec.key_len,
254                              rec.data_len, parser, private_data);
255
256         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
257
258         return ret;
259 }
260
261 /* check if an entry in the database exists
262
263    note that 1 is returned if the key is found and 0 is returned if not found
264    this doesn't match the conventions in the rest of this module, but is
265    compatible with gdbm
266 */
267 static int tdb_exists_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
268 {
269         struct tdb_record rec;
270
271         if (tdb_find_lock_hash(tdb, key, hash, F_RDLCK, &rec) == 0)
272                 return 0;
273         tdb_unlock(tdb, BUCKET(rec.full_hash), F_RDLCK);
274         return 1;
275 }
276
277 _PUBLIC_ int tdb_exists(struct tdb_context *tdb, TDB_DATA key)
278 {
279         uint32_t hash = tdb->hash_fn(&key);
280         int ret;
281
282         ret = tdb_exists_hash(tdb, key, hash);
283         tdb_trace_1rec_ret(tdb, "tdb_exists", key, ret);
284         return ret;
285 }
286
287 /* actually delete an entry in the database given the offset */
288 int tdb_do_delete(struct tdb_context *tdb, tdb_off_t rec_ptr, struct tdb_record *rec)
289 {
290         tdb_off_t last_ptr, i;
291         struct tdb_record lastrec;
292
293         if (tdb->read_only || tdb->traverse_read) return -1;
294
295         if (((tdb->traverse_write != 0) && (!TDB_DEAD(rec))) ||
296             tdb_write_lock_record(tdb, rec_ptr) == -1) {
297                 /* Someone traversing here: mark it as dead */
298                 rec->magic = TDB_DEAD_MAGIC;
299                 return tdb_rec_write(tdb, rec_ptr, rec);
300         }
301         if (tdb_write_unlock_record(tdb, rec_ptr) != 0)
302                 return -1;
303
304         /* find previous record in hash chain */
305         if (tdb_ofs_read(tdb, TDB_HASH_TOP(rec->full_hash), &i) == -1)
306                 return -1;
307         for (last_ptr = 0; i != rec_ptr; last_ptr = i, i = lastrec.next)
308                 if (tdb_rec_read(tdb, i, &lastrec) == -1)
309                         return -1;
310
311         /* unlink it: next ptr is at start of record. */
312         if (last_ptr == 0)
313                 last_ptr = TDB_HASH_TOP(rec->full_hash);
314         if (tdb_ofs_write(tdb, last_ptr, &rec->next) == -1)
315                 return -1;
316
317         /* recover the space */
318         if (tdb_free(tdb, rec_ptr, rec) == -1)
319                 return -1;
320         return 0;
321 }
322
323 static int tdb_count_dead(struct tdb_context *tdb, uint32_t hash)
324 {
325         int res = 0;
326         tdb_off_t rec_ptr;
327         struct tdb_record rec;
328
329         /* read in the hash top */
330         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
331                 return 0;
332
333         while (rec_ptr) {
334                 if (tdb_rec_read(tdb, rec_ptr, &rec) == -1)
335                         return 0;
336
337                 if (rec.magic == TDB_DEAD_MAGIC) {
338                         res += 1;
339                 }
340                 rec_ptr = rec.next;
341         }
342         return res;
343 }
344
345 /*
346  * Purge all DEAD records from a hash chain
347  */
348 static int tdb_purge_dead(struct tdb_context *tdb, uint32_t hash)
349 {
350         int res = -1;
351         struct tdb_record rec;
352         tdb_off_t rec_ptr;
353
354         if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
355                 return -1;
356         }
357
358         /* read in the hash top */
359         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
360                 goto fail;
361
362         while (rec_ptr) {
363                 tdb_off_t next;
364
365                 if (tdb_rec_read(tdb, rec_ptr, &rec) == -1) {
366                         goto fail;
367                 }
368
369                 next = rec.next;
370
371                 if (rec.magic == TDB_DEAD_MAGIC
372                     && tdb_do_delete(tdb, rec_ptr, &rec) == -1) {
373                         goto fail;
374                 }
375                 rec_ptr = next;
376         }
377         res = 0;
378  fail:
379         tdb_unlock(tdb, -1, F_WRLCK);
380         return res;
381 }
382
383 /* delete an entry in the database given a key */
384 static int tdb_delete_hash(struct tdb_context *tdb, TDB_DATA key, uint32_t hash)
385 {
386         tdb_off_t rec_ptr;
387         struct tdb_record rec;
388         int ret;
389
390         rec_ptr = tdb_find_lock_hash(tdb, key, hash, F_WRLCK, &rec);
391         if (rec_ptr == 0) {
392                 return -1;
393         }
394
395         if (tdb->max_dead_records != 0) {
396
397                 /*
398                  * Allow for some dead records per hash chain, mainly for
399                  * tdb's with a very high create/delete rate like locking.tdb.
400                  */
401
402                 if (tdb_count_dead(tdb, hash) >= tdb->max_dead_records) {
403                         /*
404                          * Don't let the per-chain freelist grow too large,
405                          * delete all existing dead records
406                          */
407                         tdb_purge_dead(tdb, hash);
408                 }
409
410                 /*
411                  * Just mark the record as dead.
412                  */
413                 rec.magic = TDB_DEAD_MAGIC;
414                 ret = tdb_rec_write(tdb, rec_ptr, &rec);
415         }
416         else {
417                 ret = tdb_do_delete(tdb, rec_ptr, &rec);
418         }
419
420         if (ret == 0) {
421                 tdb_increment_seqnum(tdb);
422         }
423
424         if (tdb_unlock(tdb, BUCKET(hash), F_WRLCK) != 0)
425                 TDB_LOG((tdb, TDB_DEBUG_WARNING, "tdb_delete: WARNING tdb_unlock failed!\n"));
426         return ret;
427 }
428
429 _PUBLIC_ int tdb_delete(struct tdb_context *tdb, TDB_DATA key)
430 {
431         uint32_t hash = tdb->hash_fn(&key);
432         int ret;
433
434         ret = tdb_delete_hash(tdb, key, hash);
435         tdb_trace_1rec_ret(tdb, "tdb_delete", key, ret);
436         return ret;
437 }
438
439 /*
440  * See if we have a dead record around with enough space
441  */
442 static tdb_off_t tdb_find_dead(struct tdb_context *tdb, uint32_t hash,
443                                struct tdb_record *r, tdb_len_t length)
444 {
445         tdb_off_t rec_ptr;
446
447         /* read in the hash top */
448         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1)
449                 return 0;
450
451         /* keep looking until we find the right record */
452         while (rec_ptr) {
453                 if (tdb_rec_read(tdb, rec_ptr, r) == -1)
454                         return 0;
455
456                 if (TDB_DEAD(r) && r->rec_len >= length) {
457                         /*
458                          * First fit for simple coding, TODO: change to best
459                          * fit
460                          */
461                         return rec_ptr;
462                 }
463                 rec_ptr = r->next;
464         }
465         return 0;
466 }
467
468 static int _tdb_store(struct tdb_context *tdb, TDB_DATA key,
469                        TDB_DATA dbuf, int flag, uint32_t hash)
470 {
471         struct tdb_record rec;
472         tdb_off_t rec_ptr;
473         int ret = -1;
474
475         /* check for it existing, on insert. */
476         if (flag == TDB_INSERT) {
477                 if (tdb_exists_hash(tdb, key, hash)) {
478                         tdb->ecode = TDB_ERR_EXISTS;
479                         goto fail;
480                 }
481         } else {
482                 /* first try in-place update, on modify or replace. */
483                 if (tdb_update_hash(tdb, key, hash, dbuf) == 0) {
484                         goto done;
485                 }
486                 if (tdb->ecode == TDB_ERR_NOEXIST &&
487                     flag == TDB_MODIFY) {
488                         /* if the record doesn't exist and we are in TDB_MODIFY mode then
489                          we should fail the store */
490                         goto fail;
491                 }
492         }
493         /* reset the error code potentially set by the tdb_update() */
494         tdb->ecode = TDB_SUCCESS;
495
496         /* delete any existing record - if it doesn't exist we don't
497            care.  Doing this first reduces fragmentation, and avoids
498            coalescing with `allocated' block before it's updated. */
499         if (flag != TDB_INSERT)
500                 tdb_delete_hash(tdb, key, hash);
501
502         if (tdb->max_dead_records != 0) {
503                 /*
504                  * Allow for some dead records per hash chain, look if we can
505                  * find one that can hold the new record. We need enough space
506                  * for key, data and tailer. If we find one, we don't have to
507                  * consult the central freelist.
508                  */
509                 rec_ptr = tdb_find_dead(
510                         tdb, hash, &rec,
511                         key.dsize + dbuf.dsize + sizeof(tdb_off_t));
512
513                 if (rec_ptr != 0) {
514                         rec.key_len = key.dsize;
515                         rec.data_len = dbuf.dsize;
516                         rec.full_hash = hash;
517                         rec.magic = TDB_MAGIC;
518                         if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
519                             || tdb->methods->tdb_write(
520                                     tdb, rec_ptr + sizeof(rec),
521                                     key.dptr, key.dsize) == -1
522                             || tdb->methods->tdb_write(
523                                     tdb, rec_ptr + sizeof(rec) + key.dsize,
524                                     dbuf.dptr, dbuf.dsize) == -1) {
525                                 goto fail;
526                         }
527                         goto done;
528                 }
529         }
530
531         /*
532          * We have to allocate some space from the freelist, so this means we
533          * have to lock it. Use the chance to purge all the DEAD records from
534          * the hash chain under the freelist lock.
535          */
536
537         if (tdb_lock(tdb, -1, F_WRLCK) == -1) {
538                 goto fail;
539         }
540
541         if ((tdb->max_dead_records != 0)
542             && (tdb_purge_dead(tdb, hash) == -1)) {
543                 tdb_unlock(tdb, -1, F_WRLCK);
544                 goto fail;
545         }
546
547         /* we have to allocate some space */
548         rec_ptr = tdb_allocate(tdb, key.dsize + dbuf.dsize, &rec);
549
550         tdb_unlock(tdb, -1, F_WRLCK);
551
552         if (rec_ptr == 0) {
553                 goto fail;
554         }
555
556         /* Read hash top into next ptr */
557         if (tdb_ofs_read(tdb, TDB_HASH_TOP(hash), &rec.next) == -1)
558                 goto fail;
559
560         rec.key_len = key.dsize;
561         rec.data_len = dbuf.dsize;
562         rec.full_hash = hash;
563         rec.magic = TDB_MAGIC;
564
565         /* write out and point the top of the hash chain at it */
566         if (tdb_rec_write(tdb, rec_ptr, &rec) == -1
567             || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec),
568                                        key.dptr, key.dsize) == -1
569             || tdb->methods->tdb_write(tdb, rec_ptr+sizeof(rec)+key.dsize,
570                                        dbuf.dptr, dbuf.dsize) == -1
571             || tdb_ofs_write(tdb, TDB_HASH_TOP(hash), &rec_ptr) == -1) {
572                 /* Need to tdb_unallocate() here */
573                 goto fail;
574         }
575
576  done:
577         ret = 0;
578  fail:
579         if (ret == 0) {
580                 tdb_increment_seqnum(tdb);
581         }
582         return ret;
583 }
584
585 /* store an element in the database, replacing any existing element
586    with the same key
587
588    return 0 on success, -1 on failure
589 */
590 _PUBLIC_ int tdb_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf, int flag)
591 {
592         uint32_t hash;
593         int ret;
594
595         if (tdb->read_only || tdb->traverse_read) {
596                 tdb->ecode = TDB_ERR_RDONLY;
597                 tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, -1);
598                 return -1;
599         }
600
601         /* find which hash bucket it is in */
602         hash = tdb->hash_fn(&key);
603         if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
604                 return -1;
605
606         ret = _tdb_store(tdb, key, dbuf, flag, hash);
607         tdb_trace_2rec_flag_ret(tdb, "tdb_store", key, dbuf, flag, ret);
608         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
609         return ret;
610 }
611
612 /* Append to an entry. Create if not exist. */
613 _PUBLIC_ int tdb_append(struct tdb_context *tdb, TDB_DATA key, TDB_DATA new_dbuf)
614 {
615         uint32_t hash;
616         TDB_DATA dbuf;
617         int ret = -1;
618
619         /* find which hash bucket it is in */
620         hash = tdb->hash_fn(&key);
621         if (tdb_lock(tdb, BUCKET(hash), F_WRLCK) == -1)
622                 return -1;
623
624         dbuf = _tdb_fetch(tdb, key);
625
626         if (dbuf.dptr == NULL) {
627                 dbuf.dptr = (unsigned char *)malloc(new_dbuf.dsize);
628         } else {
629                 unsigned int new_len = dbuf.dsize + new_dbuf.dsize;
630                 unsigned char *new_dptr;
631
632                 /* realloc '0' is special: don't do that. */
633                 if (new_len == 0)
634                         new_len = 1;
635                 new_dptr = (unsigned char *)realloc(dbuf.dptr, new_len);
636                 if (new_dptr == NULL) {
637                         free(dbuf.dptr);
638                 }
639                 dbuf.dptr = new_dptr;
640         }
641
642         if (dbuf.dptr == NULL) {
643                 tdb->ecode = TDB_ERR_OOM;
644                 goto failed;
645         }
646
647         memcpy(dbuf.dptr + dbuf.dsize, new_dbuf.dptr, new_dbuf.dsize);
648         dbuf.dsize += new_dbuf.dsize;
649
650         ret = _tdb_store(tdb, key, dbuf, 0, hash);
651         tdb_trace_2rec_retrec(tdb, "tdb_append", key, new_dbuf, dbuf);
652
653 failed:
654         tdb_unlock(tdb, BUCKET(hash), F_WRLCK);
655         SAFE_FREE(dbuf.dptr);
656         return ret;
657 }
658
659
660 /*
661   return the name of the current tdb file
662   useful for external logging functions
663 */
664 _PUBLIC_ const char *tdb_name(struct tdb_context *tdb)
665 {
666         return tdb->name;
667 }
668
669 /*
670   return the underlying file descriptor being used by tdb, or -1
671   useful for external routines that want to check the device/inode
672   of the fd
673 */
674 _PUBLIC_ int tdb_fd(struct tdb_context *tdb)
675 {
676         return tdb->fd;
677 }
678
679 /*
680   return the current logging function
681   useful for external tdb routines that wish to log tdb errors
682 */
683 _PUBLIC_ tdb_log_func tdb_log_fn(struct tdb_context *tdb)
684 {
685         return tdb->log.log_fn;
686 }
687
688
689 /*
690   get the tdb sequence number. Only makes sense if the writers opened
691   with TDB_SEQNUM set. Note that this sequence number will wrap quite
692   quickly, so it should only be used for a 'has something changed'
693   test, not for code that relies on the count of the number of changes
694   made. If you want a counter then use a tdb record.
695
696   The aim of this sequence number is to allow for a very lightweight
697   test of a possible tdb change.
698 */
699 _PUBLIC_ int tdb_get_seqnum(struct tdb_context *tdb)
700 {
701         tdb_off_t seqnum=0;
702
703         tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
704         return seqnum;
705 }
706
707 _PUBLIC_ int tdb_hash_size(struct tdb_context *tdb)
708 {
709         return tdb->hash_size;
710 }
711
712 _PUBLIC_ size_t tdb_map_size(struct tdb_context *tdb)
713 {
714         return tdb->map_size;
715 }
716
717 _PUBLIC_ int tdb_get_flags(struct tdb_context *tdb)
718 {
719         return tdb->flags;
720 }
721
722 _PUBLIC_ void tdb_add_flags(struct tdb_context *tdb, unsigned flags)
723 {
724         if ((flags & TDB_ALLOW_NESTING) &&
725             (flags & TDB_DISALLOW_NESTING)) {
726                 tdb->ecode = TDB_ERR_NESTING;
727                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_add_flags: "
728                         "allow_nesting and disallow_nesting are not allowed together!"));
729                 return;
730         }
731
732         if (flags & TDB_ALLOW_NESTING) {
733                 tdb->flags &= ~TDB_DISALLOW_NESTING;
734         }
735         if (flags & TDB_DISALLOW_NESTING) {
736                 tdb->flags &= ~TDB_ALLOW_NESTING;
737         }
738
739         tdb->flags |= flags;
740 }
741
742 _PUBLIC_ void tdb_remove_flags(struct tdb_context *tdb, unsigned flags)
743 {
744         if ((flags & TDB_ALLOW_NESTING) &&
745             (flags & TDB_DISALLOW_NESTING)) {
746                 tdb->ecode = TDB_ERR_NESTING;
747                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_remove_flags: "
748                         "allow_nesting and disallow_nesting are not allowed together!"));
749                 return;
750         }
751
752         if (flags & TDB_ALLOW_NESTING) {
753                 tdb->flags |= TDB_DISALLOW_NESTING;
754         }
755         if (flags & TDB_DISALLOW_NESTING) {
756                 tdb->flags |= TDB_ALLOW_NESTING;
757         }
758
759         tdb->flags &= ~flags;
760 }
761
762
763 /*
764   enable sequence number handling on an open tdb
765 */
766 _PUBLIC_ void tdb_enable_seqnum(struct tdb_context *tdb)
767 {
768         tdb->flags |= TDB_SEQNUM;
769 }
770
771
772 /*
773   add a region of the file to the freelist. Length is the size of the region in bytes,
774   which includes the free list header that needs to be added
775  */
776 static int tdb_free_region(struct tdb_context *tdb, tdb_off_t offset, ssize_t length)
777 {
778         struct tdb_record rec;
779         if (length <= sizeof(rec)) {
780                 /* the region is not worth adding */
781                 return 0;
782         }
783         if (length + offset > tdb->map_size) {
784                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: adding region beyond end of file\n"));
785                 return -1;
786         }
787         memset(&rec,'\0',sizeof(rec));
788         rec.rec_len = length - sizeof(rec);
789         if (tdb_free(tdb, offset, &rec) == -1) {
790                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_free_region: failed to add free record\n"));
791                 return -1;
792         }
793         return 0;
794 }
795
796 /*
797   wipe the entire database, deleting all records. This can be done
798   very fast by using a allrecord lock. The entire data portion of the
799   file becomes a single entry in the freelist.
800
801   This code carefully steps around the recovery area, leaving it alone
802  */
803 _PUBLIC_ int tdb_wipe_all(struct tdb_context *tdb)
804 {
805         int i;
806         tdb_off_t offset = 0;
807         ssize_t data_len;
808         tdb_off_t recovery_head;
809         tdb_len_t recovery_size = 0;
810
811         if (tdb_lockall(tdb) != 0) {
812                 return -1;
813         }
814
815         tdb_trace(tdb, "tdb_wipe_all");
816
817         /* see if the tdb has a recovery area, and remember its size
818            if so. We don't want to lose this as otherwise each
819            tdb_wipe_all() in a transaction will increase the size of
820            the tdb by the size of the recovery area */
821         if (tdb_ofs_read(tdb, TDB_RECOVERY_HEAD, &recovery_head) == -1) {
822                 TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery head\n"));
823                 goto failed;
824         }
825
826         if (recovery_head != 0) {
827                 struct tdb_record rec;
828                 if (tdb->methods->tdb_read(tdb, recovery_head, &rec, sizeof(rec), DOCONV()) == -1) {
829                         TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_wipe_all: failed to read recovery record\n"));
830                         return -1;
831                 }
832                 recovery_size = rec.rec_len + sizeof(rec);
833         }
834
835         /* wipe the hashes */
836         for (i=0;i<tdb->hash_size;i++) {
837                 if (tdb_ofs_write(tdb, TDB_HASH_TOP(i), &offset) == -1) {
838                         TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write hash %d\n", i));
839                         goto failed;
840                 }
841         }
842
843         /* wipe the freelist */
844         if (tdb_ofs_write(tdb, FREELIST_TOP, &offset) == -1) {
845                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to write freelist\n"));
846                 goto failed;
847         }
848
849         /* add all the rest of the file to the freelist, possibly leaving a gap
850            for the recovery area */
851         if (recovery_size == 0) {
852                 /* the simple case - the whole file can be used as a freelist */
853                 data_len = (tdb->map_size - TDB_DATA_START(tdb->hash_size));
854                 if (tdb_free_region(tdb, TDB_DATA_START(tdb->hash_size), data_len) != 0) {
855                         goto failed;
856                 }
857         } else {
858                 /* we need to add two freelist entries - one on either
859                    side of the recovery area
860
861                    Note that we cannot shift the recovery area during
862                    this operation. Only the transaction.c code may
863                    move the recovery area or we risk subtle data
864                    corruption
865                 */
866                 data_len = (recovery_head - TDB_DATA_START(tdb->hash_size));
867                 if (tdb_free_region(tdb, TDB_DATA_START(tdb->hash_size), data_len) != 0) {
868                         goto failed;
869                 }
870                 /* and the 2nd free list entry after the recovery area - if any */
871                 data_len = tdb->map_size - (recovery_head+recovery_size);
872                 if (tdb_free_region(tdb, recovery_head+recovery_size, data_len) != 0) {
873                         goto failed;
874                 }
875         }
876
877         tdb_increment_seqnum_nonblock(tdb);
878
879         if (tdb_unlockall(tdb) != 0) {
880                 TDB_LOG((tdb, TDB_DEBUG_FATAL,"tdb_wipe_all: failed to unlock\n"));
881                 goto failed;
882         }
883
884         return 0;
885
886 failed:
887         tdb_unlockall(tdb);
888         return -1;
889 }
890
891 struct traverse_state {
892         bool error;
893         struct tdb_context *dest_db;
894 };
895
896 /*
897   traverse function for repacking
898  */
899 static int repack_traverse(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, void *private_data)
900 {
901         struct traverse_state *state = (struct traverse_state *)private_data;
902         if (tdb_store(state->dest_db, key, data, TDB_INSERT) != 0) {
903                 state->error = true;
904                 return -1;
905         }
906         return 0;
907 }
908
909 /*
910   repack a tdb
911  */
912 _PUBLIC_ int tdb_repack(struct tdb_context *tdb)
913 {
914         struct tdb_context *tmp_db;
915         struct traverse_state state;
916
917         tdb_trace(tdb, "tdb_repack");
918
919         if (tdb_transaction_start(tdb) != 0) {
920                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to start transaction\n"));
921                 return -1;
922         }
923
924         tmp_db = tdb_open("tmpdb", tdb_hash_size(tdb), TDB_INTERNAL, O_RDWR|O_CREAT, 0);
925         if (tmp_db == NULL) {
926                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to create tmp_db\n"));
927                 tdb_transaction_cancel(tdb);
928                 return -1;
929         }
930
931         state.error = false;
932         state.dest_db = tmp_db;
933
934         if (tdb_traverse_read(tdb, repack_traverse, &state) == -1) {
935                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying out\n"));
936                 tdb_transaction_cancel(tdb);
937                 tdb_close(tmp_db);
938                 return -1;
939         }
940
941         if (state.error) {
942                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during traversal\n"));
943                 tdb_transaction_cancel(tdb);
944                 tdb_close(tmp_db);
945                 return -1;
946         }
947
948         if (tdb_wipe_all(tdb) != 0) {
949                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to wipe database\n"));
950                 tdb_transaction_cancel(tdb);
951                 tdb_close(tmp_db);
952                 return -1;
953         }
954
955         state.error = false;
956         state.dest_db = tdb;
957
958         if (tdb_traverse_read(tmp_db, repack_traverse, &state) == -1) {
959                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to traverse copying back\n"));
960                 tdb_transaction_cancel(tdb);
961                 tdb_close(tmp_db);
962                 return -1;
963         }
964
965         if (state.error) {
966                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Error during second traversal\n"));
967                 tdb_transaction_cancel(tdb);
968                 tdb_close(tmp_db);
969                 return -1;
970         }
971
972         tdb_close(tmp_db);
973
974         if (tdb_transaction_commit(tdb) != 0) {
975                 TDB_LOG((tdb, TDB_DEBUG_FATAL, __location__ " Failed to commit\n"));
976                 return -1;
977         }
978
979         return 0;
980 }
981
982 /* Even on files, we can get partial writes due to signals. */
983 bool tdb_write_all(int fd, const void *buf, size_t count)
984 {
985         while (count) {
986                 ssize_t ret;
987                 ret = write(fd, buf, count);
988                 if (ret < 0)
989                         return false;
990                 buf = (const char *)buf + ret;
991                 count -= ret;
992         }
993         return true;
994 }
995
996 bool tdb_add_off_t(tdb_off_t a, tdb_off_t b, tdb_off_t *pret)
997 {
998         tdb_off_t ret = a + b;
999
1000         if ((ret < a) || (ret < b)) {
1001                 return false;
1002         }
1003         *pret = ret;
1004         return true;
1005 }
1006
1007 #ifdef TDB_TRACE
1008 static void tdb_trace_write(struct tdb_context *tdb, const char *str)
1009 {
1010         if (!tdb_write_all(tdb->tracefd, str, strlen(str))) {
1011                 close(tdb->tracefd);
1012                 tdb->tracefd = -1;
1013         }
1014 }
1015
1016 static void tdb_trace_start(struct tdb_context *tdb)
1017 {
1018         tdb_off_t seqnum=0;
1019         char msg[sizeof(tdb_off_t) * 4 + 1];
1020
1021         tdb_ofs_read(tdb, TDB_SEQNUM_OFS, &seqnum);
1022         snprintf(msg, sizeof(msg), "%u ", seqnum);
1023         tdb_trace_write(tdb, msg);
1024 }
1025
1026 static void tdb_trace_end(struct tdb_context *tdb)
1027 {
1028         tdb_trace_write(tdb, "\n");
1029 }
1030
1031 static void tdb_trace_end_ret(struct tdb_context *tdb, int ret)
1032 {
1033         char msg[sizeof(ret) * 4 + 4];
1034         snprintf(msg, sizeof(msg), " = %i\n", ret);
1035         tdb_trace_write(tdb, msg);
1036 }
1037
1038 static void tdb_trace_record(struct tdb_context *tdb, TDB_DATA rec)
1039 {
1040         char msg[20 + rec.dsize*2], *p;
1041         unsigned int i;
1042
1043         /* We differentiate zero-length records from non-existent ones. */
1044         if (rec.dptr == NULL) {
1045                 tdb_trace_write(tdb, " NULL");
1046                 return;
1047         }
1048
1049         /* snprintf here is purely cargo-cult programming. */
1050         p = msg;
1051         p += snprintf(p, sizeof(msg), " %zu:", rec.dsize);
1052         for (i = 0; i < rec.dsize; i++)
1053                 p += snprintf(p, 2, "%02x", rec.dptr[i]);
1054
1055         tdb_trace_write(tdb, msg);
1056 }
1057
1058 void tdb_trace(struct tdb_context *tdb, const char *op)
1059 {
1060         tdb_trace_start(tdb);
1061         tdb_trace_write(tdb, op);
1062         tdb_trace_end(tdb);
1063 }
1064
1065 void tdb_trace_seqnum(struct tdb_context *tdb, uint32_t seqnum, const char *op)
1066 {
1067         char msg[sizeof(tdb_off_t) * 4 + 1];
1068
1069         snprintf(msg, sizeof(msg), "%u ", seqnum);
1070         tdb_trace_write(tdb, msg);
1071         tdb_trace_write(tdb, op);
1072         tdb_trace_end(tdb);
1073 }
1074
1075 void tdb_trace_open(struct tdb_context *tdb, const char *op,
1076                     unsigned hash_size, unsigned tdb_flags, unsigned open_flags)
1077 {
1078         char msg[128];
1079
1080         snprintf(msg, sizeof(msg),
1081                  "%s %u 0x%x 0x%x", op, hash_size, tdb_flags, open_flags);
1082         tdb_trace_start(tdb);
1083         tdb_trace_write(tdb, msg);
1084         tdb_trace_end(tdb);
1085 }
1086
1087 void tdb_trace_ret(struct tdb_context *tdb, const char *op, int ret)
1088 {
1089         tdb_trace_start(tdb);
1090         tdb_trace_write(tdb, op);
1091         tdb_trace_end_ret(tdb, ret);
1092 }
1093
1094 void tdb_trace_retrec(struct tdb_context *tdb, const char *op, TDB_DATA ret)
1095 {
1096         tdb_trace_start(tdb);
1097         tdb_trace_write(tdb, op);
1098         tdb_trace_write(tdb, " =");
1099         tdb_trace_record(tdb, ret);
1100         tdb_trace_end(tdb);
1101 }
1102
1103 void tdb_trace_1rec(struct tdb_context *tdb, const char *op,
1104                     TDB_DATA rec)
1105 {
1106         tdb_trace_start(tdb);
1107         tdb_trace_write(tdb, op);
1108         tdb_trace_record(tdb, rec);
1109         tdb_trace_end(tdb);
1110 }
1111
1112 void tdb_trace_1rec_ret(struct tdb_context *tdb, const char *op,
1113                         TDB_DATA rec, int ret)
1114 {
1115         tdb_trace_start(tdb);
1116         tdb_trace_write(tdb, op);
1117         tdb_trace_record(tdb, rec);
1118         tdb_trace_end_ret(tdb, ret);
1119 }
1120
1121 void tdb_trace_1rec_retrec(struct tdb_context *tdb, const char *op,
1122                            TDB_DATA rec, TDB_DATA ret)
1123 {
1124         tdb_trace_start(tdb);
1125         tdb_trace_write(tdb, op);
1126         tdb_trace_record(tdb, rec);
1127         tdb_trace_write(tdb, " =");
1128         tdb_trace_record(tdb, ret);
1129         tdb_trace_end(tdb);
1130 }
1131
1132 void tdb_trace_2rec_flag_ret(struct tdb_context *tdb, const char *op,
1133                              TDB_DATA rec1, TDB_DATA rec2, unsigned flag,
1134                              int ret)
1135 {
1136         char msg[1 + sizeof(ret) * 4];
1137
1138         snprintf(msg, sizeof(msg), " %#x", flag);
1139         tdb_trace_start(tdb);
1140         tdb_trace_write(tdb, op);
1141         tdb_trace_record(tdb, rec1);
1142         tdb_trace_record(tdb, rec2);
1143         tdb_trace_write(tdb, msg);
1144         tdb_trace_end_ret(tdb, ret);
1145 }
1146
1147 void tdb_trace_2rec_retrec(struct tdb_context *tdb, const char *op,
1148                            TDB_DATA rec1, TDB_DATA rec2, TDB_DATA ret)
1149 {
1150         tdb_trace_start(tdb);
1151         tdb_trace_write(tdb, op);
1152         tdb_trace_record(tdb, rec1);
1153         tdb_trace_record(tdb, rec2);
1154         tdb_trace_write(tdb, " =");
1155         tdb_trace_record(tdb, ret);
1156         tdb_trace_end(tdb);
1157 }
1158 #endif