s3: Add talloc_dict.[ch]
[metze/samba/wip.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
22 struct talloc_dict {
23         struct db_context *db;
24 };
25
26 struct talloc_dict *talloc_dict_init(TALLOC_CTX *mem_ctx)
27 {
28         struct talloc_dict *result;
29
30         result = talloc(mem_ctx, struct talloc_dict);
31         if (result == NULL) {
32                 return NULL;
33         }
34         result->db = db_open_rbt(result);
35         if (result->db == NULL) {
36                 TALLOC_FREE(result);
37                 return NULL;
38         }
39         return result;
40 }
41
42 /*
43  * Add a talloced object to the dict. Nulls out the pointer to indicate that
44  * the talloc ownership has been taken. If an object for "key" already exists,
45  * the existing object is talloc_free()ed and overwritten by the new
46  * object. If "data" is NULL, object for key "key" is deleted. Return false
47  * for "no memory".
48  */
49
50 bool talloc_dict_set(struct talloc_dict *dict, DATA_BLOB key, void *pdata)
51 {
52         struct db_record *rec;
53         NTSTATUS status = NT_STATUS_OK;
54         void *data = *(void **)pdata;
55
56         rec = dict->db->fetch_locked(dict->db, talloc_tos(),
57                                      make_tdb_data(key.data, key.length));
58         if (rec == NULL) {
59                 return false;
60         }
61         if (rec->value.dsize != 0) {
62                 void *old_data;
63                 if (rec->value.dsize != sizeof(void *)) {
64                         TALLOC_FREE(rec);
65                         return false;
66                 }
67                 old_data = *(void **)(rec->value.dptr);
68                 TALLOC_FREE(old_data);
69                 if (data == NULL) {
70                         status = rec->delete_rec(rec);
71                 }
72         }
73         if (data != NULL) {
74                 void *mydata = talloc_move(dict->db, &data);
75                 *(void **)pdata = NULL;
76                 status = rec->store(rec, make_tdb_data((uint8_t *)&mydata,
77                                                        sizeof(mydata)), 0);
78         }
79         TALLOC_FREE(rec);
80         return NT_STATUS_IS_OK(status);
81 }
82
83 /*
84  * Fetch a talloced object. If "mem_ctx!=NULL", talloc_move the object there
85  * and delete it from the dict.
86  */
87
88 void *talloc_dict_fetch(struct talloc_dict *dict, DATA_BLOB key,
89                         TALLOC_CTX *mem_ctx)
90 {
91         struct db_record *rec;
92         void *result;
93
94         rec = dict->db->fetch_locked(dict->db, talloc_tos(),
95                                      make_tdb_data(key.data, key.length));
96         if (rec == NULL) {
97                 return NULL;
98         }
99         if (rec->value.dsize != sizeof(void *)) {
100                 TALLOC_FREE(rec);
101                 return NULL;
102         }
103         result = *(void **)rec->value.dptr;
104
105         if (mem_ctx != NULL) {
106                 NTSTATUS status;
107                 status = rec->delete_rec(rec);
108                 if (!NT_STATUS_IS_OK(status)) {
109                         TALLOC_FREE(rec);
110                         return NULL;
111                 }
112                 result = talloc_move(mem_ctx, &result);
113         }
114
115         return result;
116 }
117
118 struct talloc_dict_traverse_state {
119         int (*fn)(DATA_BLOB key, void *data, void *private_data);
120         void *private_data;
121 };
122
123 static int talloc_dict_traverse_fn(struct db_record *rec, void *private_data)
124 {
125         struct talloc_dict_traverse_state *state =
126                 (struct talloc_dict_traverse_state *)private_data;
127
128         if (rec->value.dsize != sizeof(void *)) {
129                 return -1;
130         }
131         return state->fn(data_blob_const(rec->key.dptr, rec->key.dsize),
132                          *(void **)rec->value.dptr, state->private_data);
133 }
134
135 /*
136  * Traverse a talloc_dict. If "fn" returns non-null, quit the traverse
137  */
138
139 int talloc_dict_traverse(struct talloc_dict *dict,
140                          int (*fn)(DATA_BLOB key, void *data,
141                                    void *private_data),
142                          void *private_data)
143 {
144         struct talloc_dict_traverse_state state;
145         state.fn = fn;
146         state.private_data = private_data;
147         return dict->db->traverse(dict->db, talloc_dict_traverse_fn, &state);
148 }