/src/samba/lib/tdb/common/freelistcheck.c
Line | Count | Source (jump to first uncovered line) |
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 | | static int seen_insert(struct tdb_context *mem_tdb, tdb_off_t rec_ptr) |
37 | 0 | { |
38 | 0 | TDB_DATA key; |
39 | |
|
40 | 0 | key.dptr = (unsigned char *)&rec_ptr; |
41 | 0 | key.dsize = sizeof(rec_ptr); |
42 | 0 | return tdb_store(mem_tdb, key, tdb_null, TDB_INSERT); |
43 | 0 | } |
44 | | |
45 | | _PUBLIC_ int tdb_validate_freelist(struct tdb_context *tdb, int *pnum_entries) |
46 | 0 | { |
47 | 0 | struct tdb_context *mem_tdb = NULL; |
48 | 0 | struct tdb_record rec; |
49 | 0 | tdb_off_t rec_ptr, last_ptr; |
50 | 0 | int ret = -1; |
51 | |
|
52 | 0 | *pnum_entries = 0; |
53 | |
|
54 | 0 | mem_tdb = tdb_open("flval", tdb->hash_size, |
55 | 0 | TDB_INTERNAL, O_RDWR, 0600); |
56 | 0 | if (!mem_tdb) { |
57 | 0 | return -1; |
58 | 0 | } |
59 | | |
60 | 0 | if (tdb_lock(tdb, -1, F_WRLCK) == -1) { |
61 | 0 | tdb_close(mem_tdb); |
62 | 0 | return 0; |
63 | 0 | } |
64 | | |
65 | 0 | last_ptr = FREELIST_TOP; |
66 | | |
67 | | /* Store the FREELIST_TOP record. */ |
68 | 0 | if (seen_insert(mem_tdb, last_ptr) == -1) { |
69 | 0 | tdb->ecode = TDB_ERR_CORRUPT; |
70 | 0 | ret = -1; |
71 | 0 | goto fail; |
72 | 0 | } |
73 | | |
74 | | /* read in the freelist top */ |
75 | 0 | if (tdb_ofs_read(tdb, FREELIST_TOP, &rec_ptr) == -1) { |
76 | 0 | goto fail; |
77 | 0 | } |
78 | | |
79 | 0 | 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 | 0 | if (seen_insert(mem_tdb, rec_ptr)) { |
86 | 0 | tdb->ecode = TDB_ERR_CORRUPT; |
87 | 0 | ret = -1; |
88 | 0 | goto fail; |
89 | 0 | } |
90 | | |
91 | 0 | if (tdb_rec_free_read(tdb, rec_ptr, &rec) == -1) { |
92 | 0 | goto fail; |
93 | 0 | } |
94 | | |
95 | | /* move to the next record */ |
96 | 0 | rec_ptr = rec.next; |
97 | 0 | *pnum_entries += 1; |
98 | 0 | } |
99 | | |
100 | 0 | ret = 0; |
101 | |
|
102 | 0 | fail: |
103 | |
|
104 | 0 | tdb_close(mem_tdb); |
105 | 0 | tdb_unlock(tdb, -1, F_WRLCK); |
106 | 0 | return ret; |
107 | 0 | } |