1/* 2 Unix SMB/CIFS implementation. 3 4 trivial database library 5 6 Copyright (C) Jeremy Allison 2006 7 8 ** NOTE! The following LGPL license applies to the tdb 9 ** library. This does NOT imply that all of Samba is released 10 ** under the LGPL 11 12 This library is free software; you can redistribute it and/or 13 modify it under the terms of the GNU Lesser General Public 14 License as published by the Free Software Foundation; either 15 version 3 of the License, or (at your option) any later version. 16 17 This library is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 Lesser General Public License for more details. 21 22 You should have received a copy of the GNU Lesser General Public 23 License along with this library; if not, see <http://www.gnu.org/licenses/>. 24*/ 25 26#include "tdb_private.h" 27 28/* Check the freelist is good and contains no loops. 29 Very memory intensive - only do this as a consistency 30 checker. Heh heh - uses an in memory tdb as the storage 31 for the "seen" record list. For some reason this strikes 32 me as extremely clever as I don't have to write another tree 33 data structure implementation :-). 34 */ 35 36static int seen_insert(struct tdb_context *mem_tdb, tdb_off_t rec_ptr) 37{ 38 TDB_DATA key, data; 39 40 memset(&data, '\0', sizeof(data)); 41 key.dptr = (unsigned char *)&rec_ptr; 42 key.dsize = sizeof(rec_ptr); 43 return tdb_store(mem_tdb, key, data, TDB_INSERT); 44} 45 46int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries) 47{ 48 struct tdb_context *mem_tdb = NULL; 49 struct tdb_record rec; 50 tdb_off_t rec_ptr, last_ptr; 51 int ret = -1; 52 53 *pnum_entries = 0; 54 55 mem_tdb = tdb_open("flval", tdb->header.hash_size, 56 TDB_INTERNAL, O_RDWR, 0600); 57 if (!mem_tdb) { 58 return -1; 59 } 60 61 if (tdb_lock(tdb, -1, F_WRLCK) == -1) { 62 tdb_close(mem_tdb); 63 return 0; 64 } 65 66 last_ptr = FREELIST_TOP; 67 68 /* Store the FREELIST_TOP record. */ 69 if (seen_insert(mem_tdb, last_ptr) == -1) { 70 tdb->ecode = TDB_ERR_CORRUPT; 71 ret = -1; 72 goto fail; 73 } 74 75 /* read in the freelist top */ 76 if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) { 77 goto fail; 78 } 79 80 while (rec_ptr) { 81 82 /* If we can't store this record (we've seen it 83 before) then the free list has a loop and must 84 be corrupt. */ 85 86 if (seen_insert(mem_tdb, rec_ptr)) { 87 tdb->ecode = TDB_ERR_CORRUPT; 88 ret = -1; 89 goto fail; 90 } 91 92 if (tdb_rec_free_read(tdb, rec_ptr, &rec) == -1) { 93 goto fail; 94 } 95 96 /* move to the next record */ 97 last_ptr = rec_ptr; 98 rec_ptr = rec.next; 99 *pnum_entries += 1; 100 } 101 102 ret = 0; 103 104 fail: 105 106 tdb_close(mem_tdb); 107 tdb_unlock(tdb, -1, F_WRLCK); 108 return ret; 109} 110