Line data Source code
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 : 36 26 : static int seen_insert(struct tdb_context *mem_tdb, tdb_off_t rec_ptr) 37 : { 38 2 : TDB_DATA key; 39 : 40 26 : key.dptr = (unsigned char *)&rec_ptr; 41 26 : key.dsize = sizeof(rec_ptr); 42 26 : return tdb_store(mem_tdb, key, tdb_null, TDB_INSERT); 43 : } 44 : 45 13 : _PUBLIC_ int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries) 46 : { 47 13 : struct tdb_context *mem_tdb = NULL; 48 1 : struct tdb_record rec; 49 1 : tdb_off_t rec_ptr, last_ptr; 50 13 : int ret = -1; 51 : 52 13 : *pnum_entries = 0; 53 : 54 13 : mem_tdb = tdb_open("flval", tdb->hash_size, 55 : TDB_INTERNAL, O_RDWR, 0600); 56 13 : if (!mem_tdb) { 57 0 : return -1; 58 : } 59 : 60 13 : if (tdb_lock(tdb, -1, F_WRLCK) == -1) { 61 0 : tdb_close(mem_tdb); 62 0 : return 0; 63 : } 64 : 65 13 : last_ptr = FREELIST_TOP; 66 : 67 : /* Store the FREELIST_TOP record. */ 68 13 : if (seen_insert(mem_tdb, last_ptr) == -1) { 69 0 : tdb->ecode = TDB_ERR_CORRUPT; 70 0 : ret = -1; 71 0 : goto fail; 72 : } 73 : 74 : /* read in the freelist top */ 75 13 : if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) { 76 0 : goto fail; 77 : } 78 : 79 26 : while (rec_ptr) { 80 : 81 : /* If we can't store this record (we've seen it 82 : before) then the free list has a loop and must 83 : be corrupt. */ 84 : 85 13 : if (seen_insert(mem_tdb, rec_ptr)) { 86 0 : tdb->ecode = TDB_ERR_CORRUPT; 87 0 : ret = -1; 88 0 : goto fail; 89 : } 90 : 91 13 : if (tdb_rec_free_read(tdb, rec_ptr, &rec) == -1) { 92 0 : goto fail; 93 : } 94 : 95 : /* move to the next record */ 96 13 : rec_ptr = rec.next; 97 13 : *pnum_entries += 1; 98 : } 99 : 100 12 : ret = 0; 101 : 102 13 : fail: 103 : 104 13 : tdb_close(mem_tdb); 105 13 : tdb_unlock(tdb, -1, F_WRLCK); 106 13 : return ret; 107 : }