r4714: move the ldb code to the new talloc interface (eg remove _p suffix)
[metze/samba/wip.git] / source4 / lib / ldb / ldb_tdb / ldb_cache.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Tridgell  2004
5
6      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9    
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 2 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ldb tdb cache functions
29  *
30  *  Description: cache special records in a ldb/tdb
31  *
32  *  Author: Andrew Tridgell
33  */
34
35 #include "includes.h"
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_private.h"
38 #include "ldb/ldb_tdb/ldb_tdb.h"
39
40 /*
41   initialise the baseinfo record
42 */
43 static int ltdb_baseinfo_init(struct ldb_module *module)
44 {
45         struct ltdb_private *ltdb = module->private_data;
46         struct ldb_message *msg;
47         struct ldb_message_element el;
48         struct ldb_val val;
49         int ret;
50         /* the initial sequence number must be different from the one
51            set in ltdb_cache_free(). Thanks to Jon for pointing this
52            out. */
53         const char *initial_sequence_number = "1";
54
55         ltdb->sequence_number = atof(initial_sequence_number);
56
57         msg = talloc(ltdb, struct ldb_message);
58         if (msg == NULL) {
59                 goto failed;
60         }
61
62         msg->num_elements = 1;
63         msg->elements = ⪙
64         msg->dn = talloc_strdup(msg, LTDB_BASEINFO);
65         if (!msg->dn) {
66                 goto failed;
67         }
68         el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
69         if (!el.name) {
70                 goto failed;
71         }
72         el.values = &val;
73         el.num_values = 1;
74         el.flags = 0;
75         val.data = talloc_strdup(msg, initial_sequence_number);
76         if (!val.data) {
77                 goto failed;
78         }
79         val.length = 1;
80         
81         ret = ltdb_store(module, msg, TDB_INSERT);
82
83         talloc_free(msg);
84
85         return ret;
86
87 failed:
88         talloc_free(msg);
89         errno = ENOMEM;
90         return -1;
91 }
92
93 /*
94   free any cache records
95  */
96 static void ltdb_cache_free(struct ldb_module *module)
97 {
98         struct ltdb_private *ltdb = module->private_data;
99
100         ltdb->sequence_number = 0;
101         talloc_free(ltdb->cache);
102         ltdb->cache = NULL;
103 }
104
105 /*
106   force a cache reload
107 */
108 int ltdb_cache_reload(struct ldb_module *module)
109 {
110         ltdb_cache_free(module);
111         return ltdb_cache_load(module);
112 }
113
114 /*
115   load the cache records
116 */
117 int ltdb_cache_load(struct ldb_module *module)
118 {
119         struct ltdb_private *ltdb = module->private_data;
120         double seq;
121
122         if (ltdb->cache == NULL) {
123                 ltdb->cache = talloc_zero(ltdb, struct ltdb_cache);
124                 if (ltdb->cache == NULL) goto failed;
125                 ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message);
126                 ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message);
127                 ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message);
128                 if (ltdb->cache->indexlist == NULL ||
129                     ltdb->cache->subclasses == NULL ||
130                     ltdb->cache->attributes == NULL) {
131                         goto failed;
132                 }
133         }
134
135         talloc_free(ltdb->cache->baseinfo);
136         ltdb->cache->baseinfo = talloc(ltdb->cache, struct ldb_message);
137         if (ltdb->cache->baseinfo == NULL) goto failed;
138         
139         if (ltdb_search_dn1(module, LTDB_BASEINFO, ltdb->cache->baseinfo) == -1) {
140                 goto failed;
141         }
142         
143         /* possibly initialise the baseinfo */
144         if (!ltdb->cache->baseinfo->dn) {
145                 if (ltdb_baseinfo_init(module) != 0) {
146                         goto failed;
147                 }
148                 if (ltdb_search_dn1(module, LTDB_BASEINFO, ltdb->cache->baseinfo) != 1) {
149                         goto failed;
150                 }
151         }
152
153         /* if the current internal sequence number is the same as the one
154            in the database then assume the rest of the cache is OK */
155         seq = ldb_msg_find_double(ltdb->cache->baseinfo, LTDB_SEQUENCE_NUMBER, 0);
156         if (seq == ltdb->sequence_number) {
157                 goto done;
158         }
159         ltdb->sequence_number = seq;
160
161         talloc_free(ltdb->cache->last_attribute.name);
162         memset(&ltdb->cache->last_attribute, 0, sizeof(ltdb->cache->last_attribute));
163
164         talloc_free(ltdb->cache->indexlist);
165         talloc_free(ltdb->cache->subclasses);
166         talloc_free(ltdb->cache->attributes);
167
168         ltdb->cache->indexlist = talloc_zero(ltdb->cache, struct ldb_message);
169         ltdb->cache->subclasses = talloc_zero(ltdb->cache, struct ldb_message);
170         ltdb->cache->attributes = talloc_zero(ltdb->cache, struct ldb_message);
171         if (ltdb->cache->indexlist == NULL ||
172             ltdb->cache->subclasses == NULL ||
173             ltdb->cache->attributes == NULL) {
174                 goto failed;
175         }
176             
177         if (ltdb_search_dn1(module, LTDB_INDEXLIST, ltdb->cache->indexlist) == -1) {
178                 goto failed;
179         }
180         if (ltdb_search_dn1(module, LTDB_SUBCLASSES, ltdb->cache->subclasses) == -1) {
181                 goto failed;
182         }
183         if (ltdb_search_dn1(module, LTDB_ATTRIBUTES, ltdb->cache->attributes) == -1) {
184                 goto failed;
185         }
186
187 done:
188         return 0;
189
190 failed:
191         return -1;
192 }
193
194
195 /*
196   increase the sequence number to indicate a database change
197 */
198 int ltdb_increase_sequence_number(struct ldb_module *module)
199 {
200         struct ltdb_private *ltdb = module->private_data;
201         struct ldb_message *msg;
202         struct ldb_message_element el;
203         struct ldb_val val;
204         char *s = NULL;
205         int ret;
206
207         msg = talloc(ltdb, struct ldb_message);
208         if (msg == NULL) {
209                 errno = ENOMEM;
210                 return -1;
211         }
212
213         s = talloc_asprintf(msg, "%.0f", ltdb->sequence_number+1);
214         if (!s) {
215                 errno = ENOMEM;
216                 return -1;
217         }
218
219         msg->num_elements = 1;
220         msg->elements = ⪙
221         msg->dn = talloc_strdup(msg, LTDB_BASEINFO);
222         el.name = talloc_strdup(msg, LTDB_SEQUENCE_NUMBER);
223         el.values = &val;
224         el.num_values = 1;
225         el.flags = LDB_FLAG_MOD_REPLACE;
226         val.data = s;
227         val.length = strlen(s);
228
229         ret = ltdb_modify_internal(module, msg);
230
231         talloc_free(msg);
232
233         if (ret == 0) {
234                 ltdb->sequence_number += 1;
235         }
236
237         return ret;
238 }
239
240
241 /*
242   return the attribute flags from the @ATTRIBUTES record 
243   for the given attribute
244 */
245 int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name)
246 {
247         struct ltdb_private *ltdb = module->private_data;
248         const char *attrs;
249         const struct {
250                 const char *name;
251                 int value;
252         } names[] = {
253                 { "CASE_INSENSITIVE", LTDB_FLAG_CASE_INSENSITIVE },
254                 { "INTEGER", LTDB_FLAG_INTEGER },
255                 { "WILDCARD", LTDB_FLAG_WILDCARD },
256                 { "HIDDEN", LTDB_FLAG_HIDDEN },
257                 { NULL, 0}
258         };
259         size_t len;
260         int i, ret=0;
261
262         if (ltdb->cache->last_attribute.name &&
263             ldb_attr_cmp(ltdb->cache->last_attribute.name, attr_name) == 0) {
264                 return ltdb->cache->last_attribute.flags;
265         }
266
267         /* objectclass is a special default case */
268         if (ldb_attr_cmp(attr_name, LTDB_OBJECTCLASS) == 0) {
269                 ret = LTDB_FLAG_OBJECTCLASS | LTDB_FLAG_CASE_INSENSITIVE;
270         }
271
272         attrs = ldb_msg_find_string(ltdb->cache->attributes, attr_name, NULL);
273
274         if (!attrs) {
275                 return ret;
276         }
277
278         /* we avoid using strtok and friends due to their nasty
279            interface. This is a little trickier, but much nicer
280            from a C interface point of view */
281         while ((len = strcspn(attrs, " ,")) > 0) {
282                 for (i=0;names[i].name;i++) {
283                         if (strncmp(names[i].name, attrs, len) == 0 &&
284                             names[i].name[len] == 0) {
285                                 ret |= names[i].value;
286                         }
287                 }
288                 attrs += len;
289                 attrs += strspn(attrs, " ,");
290         }
291
292         talloc_free(ltdb->cache->last_attribute.name);
293
294         ltdb->cache->last_attribute.name = talloc_strdup(ltdb->cache, attr_name);
295         ltdb->cache->last_attribute.flags = ret;
296
297         return ret;
298 }