s3-passdb: Keep caches coherent
[idra/samba.git] / source3 / lib / talloc_dict.c
1 /*
2    Unix SMB/CIFS implementation.
3    Little dictionary style data structure based on dbwrap_rbt
4    Copyright (C) Volker Lendecke 2009
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "dbwrap/dbwrap.h"
22 #include "talloc_dict.h"
23 #include "util_tdb.h"
24
25 struct talloc_dict {
26         struct db_context *db;
27 };
28
29 struct talloc_dict *talloc_dict_init(TALLOC_CTX *mem_ctx)
30 {
31         struct talloc_dict *result;
32
33         result = talloc(mem_ctx, struct talloc_dict);
34         if (result == NULL) {
35                 return NULL;
36         }
37         result->db = db_open_rbt(result);
38         if (result->db == NULL) {
39                 TALLOC_FREE(result);
40                 return NULL;
41         }
42         return result;
43 }
44
45 /*
46  * Add a talloced object to the dict. Nulls out the pointer to indicate that
47  * the talloc ownership has been taken. If an object for "key" already exists,
48  * the existing object is talloc_free()ed and overwritten by the new
49  * object. If "data" is NULL, object for key "key" is deleted. Return false
50  * for "no memory".
51  */
52
53 bool talloc_dict_set(struct talloc_dict *dict, DATA_BLOB key, void *pdata)
54 {
55         struct db_record *rec;
56         NTSTATUS status = NT_STATUS_OK;
57         void *data = *(void **)pdata;
58
59         rec = dict->db->fetch_locked(dict->db, talloc_tos(),
60                                      make_tdb_data(key.data, key.length));
61         if (rec == NULL) {
62                 return false;
63         }
64         if (rec->value.dsize != 0) {
65                 void *old_data;
66                 if (rec->value.dsize != sizeof(void *)) {
67                         TALLOC_FREE(rec);
68                         return false;
69                 }
70                 old_data = *(void **)(rec->value.dptr);
71                 TALLOC_FREE(old_data);
72                 if (data == NULL) {
73                         status = rec->delete_rec(rec);
74                 }
75         }
76         if (data != NULL) {
77                 void *mydata = talloc_move(dict->db, &data);
78                 *(void **)pdata = NULL;
79                 status = rec->store(rec, make_tdb_data((uint8_t *)&mydata,
80                                                        sizeof(mydata)), 0);
81         }
82         TALLOC_FREE(rec);
83         return NT_STATUS_IS_OK(status);
84 }
85
86 /*
87  * Fetch a talloced object. If "mem_ctx!=NULL", talloc_move the object there
88  * and delete it from the dict.
89  */
90
91 void *talloc_dict_fetch(struct talloc_dict *dict, DATA_BLOB key,
92                         TALLOC_CTX *mem_ctx)
93 {
94         struct db_record *rec;
95         void *result;
96
97         rec = dict->db->fetch_locked(dict->db, talloc_tos(),
98                                      make_tdb_data(key.data, key.length));
99         if (rec == NULL) {
100                 return NULL;
101         }
102         if (rec->value.dsize != sizeof(void *)) {
103                 TALLOC_FREE(rec);
104                 return NULL;
105         }
106         result = *(void **)rec->value.dptr;
107
108         if (mem_ctx != NULL) {
109                 NTSTATUS status;
110                 status = rec->delete_rec(rec);
111                 if (!NT_STATUS_IS_OK(status)) {
112                         TALLOC_FREE(rec);
113                         return NULL;
114                 }
115                 result = talloc_move(mem_ctx, &result);
116         }
117
118         return result;
119 }
120
121 struct talloc_dict_traverse_state {
122         int (*fn)(DATA_BLOB key, void *data, void *private_data);
123         void *private_data;
124 };
125
126 static int talloc_dict_traverse_fn(struct db_record *rec, void *private_data)
127 {
128         struct talloc_dict_traverse_state *state =
129                 (struct talloc_dict_traverse_state *)private_data;
130
131         if (rec->value.dsize != sizeof(void *)) {
132                 return -1;
133         }
134         return state->fn(data_blob_const(rec->key.dptr, rec->key.dsize),
135                          *(void **)rec->value.dptr, state->private_data);
136 }
137
138 /*
139  * Traverse a talloc_dict. If "fn" returns non-null, quit the traverse
140  */
141
142 int talloc_dict_traverse(struct talloc_dict *dict,
143                          int (*fn)(DATA_BLOB key, void *data,
144                                    void *private_data),
145                          void *private_data)
146 {
147         struct talloc_dict_traverse_state state;
148         state.fn = fn;
149         state.private_data = private_data;
150         return dict->db->traverse(dict->db, talloc_dict_traverse_fn, &state);
151 }