a8eb9ae916e94726546fbaf7b05757a791412ec8
[samba.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 ldb_context *ldb = module->ldb;
46         struct ltdb_private *ltdb = module->private_data;
47         struct ldb_message msg;
48         struct ldb_message_element el;
49         struct ldb_val val;
50         int ret;
51         /* the initial sequence number must be different from the one
52            set in ltdb_cache_free(). Thanks to Jon for pointing this
53            out. */
54         const char *initial_sequence_number = "1";
55
56         ltdb->sequence_number = atof(initial_sequence_number);
57
58         msg.num_elements = 1;
59         msg.elements = ⪙
60         msg.dn = ldb_strdup(ldb, LTDB_BASEINFO);
61         if (!msg.dn) {
62                 errno = ENOMEM;
63                 return -1;
64         }
65         el.name = ldb_strdup(ldb, LTDB_SEQUENCE_NUMBER);
66         if (!el.name) {
67                 ldb_free(ldb, msg.dn);
68                 errno = ENOMEM;
69                 return -1;
70         }
71         el.values = &val;
72         el.num_values = 1;
73         el.flags = 0;
74         val.data = ldb_strdup(ldb, initial_sequence_number);
75         if (!val.data) {
76                 ldb_free(ldb, el.name);
77                 ldb_free(ldb, msg.dn);
78                 errno = ENOMEM;
79                 return -1;
80         }
81         val.length = 1;
82         
83         ret = ltdb_store(module, &msg, TDB_INSERT);
84
85         ldb_free(ldb, msg.dn);
86         ldb_free(ldb, el.name);
87         ldb_free(ldb, val.data);
88
89         return ret;
90 }
91
92 /*
93   free any cache records
94  */
95 void ltdb_cache_free(struct ldb_module *module)
96 {
97         struct ldb_context *ldb = module->ldb;
98         struct ltdb_private *ltdb = module->private_data;
99         struct ldb_alloc_ops alloc = ldb->alloc_ops;
100         ldb->alloc_ops.alloc = NULL;
101
102         ltdb->sequence_number = 0;
103         ltdb_search_dn1_free(module, &ltdb->cache.baseinfo);
104         ltdb_search_dn1_free(module, &ltdb->cache.indexlist);
105         ltdb_search_dn1_free(module, &ltdb->cache.subclasses);
106         ltdb_search_dn1_free(module, &ltdb->cache.attributes);
107
108         ldb_free(ldb, ltdb->cache.last_attribute.name);
109         memset(&ltdb->cache, 0, sizeof(ltdb->cache));
110
111         ldb->alloc_ops = alloc;
112 }
113
114 /*
115   load the cache records
116 */
117 int ltdb_cache_load(struct ldb_module *module)
118 {
119         struct ldb_context *ldb = module->ldb;
120         struct ltdb_private *ltdb = module->private_data;
121         double seq;
122         struct ldb_alloc_ops alloc = ldb->alloc_ops;
123
124         ldb->alloc_ops.alloc = NULL;
125
126         ltdb_search_dn1_free(module, &ltdb->cache.baseinfo);
127         
128         if (ltdb_search_dn1(module, LTDB_BASEINFO, &ltdb->cache.baseinfo) == -1) {
129                 goto failed;
130         }
131         
132         /* possibly initialise the baseinfo */
133         if (!ltdb->cache.baseinfo.dn) {
134                 if (ltdb_baseinfo_init(module) != 0) {
135                         goto failed;
136                 }
137                 if (ltdb_search_dn1(module, LTDB_BASEINFO, &ltdb->cache.baseinfo) != 1) {
138                         goto failed;
139                 }
140         }
141
142         /* if the current internal sequence number is the same as the one
143            in the database then assume the rest of the cache is OK */
144         seq = ldb_msg_find_double(&ltdb->cache.baseinfo, LTDB_SEQUENCE_NUMBER, 0);
145         if (seq == ltdb->sequence_number) {
146                 goto done;
147         }
148         ltdb->sequence_number = seq;
149
150         ldb_free(ldb, ltdb->cache.last_attribute.name);
151         memset(&ltdb->cache.last_attribute, 0, sizeof(ltdb->cache.last_attribute));
152
153         ltdb_search_dn1_free(module, &ltdb->cache.indexlist);
154         ltdb_search_dn1_free(module, &ltdb->cache.subclasses);
155         ltdb_search_dn1_free(module, &ltdb->cache.attributes);
156
157         if (ltdb_search_dn1(module, LTDB_INDEXLIST, &ltdb->cache.indexlist) == -1) {
158                 goto failed;
159         }
160         if (ltdb_search_dn1(module, LTDB_SUBCLASSES, &ltdb->cache.subclasses) == -1) {
161                 goto failed;
162         }
163         if (ltdb_search_dn1(module, LTDB_ATTRIBUTES, &ltdb->cache.attributes) == -1) {
164                 goto failed;
165         }
166
167 done:
168         ldb->alloc_ops = alloc;
169         return 0;
170
171 failed:
172         ldb->alloc_ops = alloc;
173         return -1;
174 }
175
176
177 /*
178   increase the sequence number to indicate a database change
179 */
180 int ltdb_increase_sequence_number(struct ldb_module *module)
181 {
182         struct ldb_context *ldb = module->ldb;
183         struct ltdb_private *ltdb = module->private_data;
184         struct ldb_message msg;
185         struct ldb_message_element el;
186         struct ldb_val val;
187         char *s = NULL;
188         int ret;
189
190         ldb_asprintf(ldb, &s, "%.0f", ltdb->sequence_number+1);
191         if (!s) {
192                 errno = ENOMEM;
193                 return -1;
194         }
195
196         msg.num_elements = 1;
197         msg.elements = ⪙
198         msg.dn = ldb_strdup(ldb, LTDB_BASEINFO);
199         el.name = ldb_strdup(ldb, LTDB_SEQUENCE_NUMBER);
200         el.values = &val;
201         el.num_values = 1;
202         el.flags = LDB_FLAG_MOD_REPLACE;
203         val.data = s;
204         val.length = strlen(s);
205
206         ret = ltdb_modify_internal(module, &msg);
207
208         ldb_free(ldb, s);
209         ldb_free(ldb, msg.dn);
210         ldb_free(ldb, el.name);
211
212         if (ret == 0) {
213                 ltdb->sequence_number += 1;
214         }
215
216         return ret;
217 }
218
219
220 /*
221   return the attribute flags from the @ATTRIBUTES record 
222   for the given attribute
223 */
224 int ltdb_attribute_flags(struct ldb_module *module, const char *attr_name)
225 {
226         struct ldb_context *ldb = module->ldb;
227         struct ltdb_private *ltdb = module->private_data;
228         const char *attrs;
229         const struct {
230                 const char *name;
231                 int value;
232         } names[] = {
233                 { "CASE_INSENSITIVE", LTDB_FLAG_CASE_INSENSITIVE },
234                 { "INTEGER", LTDB_FLAG_INTEGER },
235                 { "WILDCARD", LTDB_FLAG_WILDCARD },
236                 { "HIDDEN", LTDB_FLAG_HIDDEN },
237                 { NULL, 0}
238         };
239         size_t len;
240         int i, ret=0;
241         struct ldb_alloc_ops alloc = ldb->alloc_ops;
242
243         if (ltdb->cache.last_attribute.name &&
244             ldb_attr_cmp(ltdb->cache.last_attribute.name, attr_name) == 0) {
245                 return ltdb->cache.last_attribute.flags;
246         }
247
248         /* objectclass is a special default case */
249         if (ldb_attr_cmp(attr_name, LTDB_OBJECTCLASS) == 0) {
250                 ret = LTDB_FLAG_OBJECTCLASS | LTDB_FLAG_CASE_INSENSITIVE;
251         }
252
253         attrs = ldb_msg_find_string(&ltdb->cache.attributes, attr_name, NULL);
254
255         if (!attrs) {
256                 return ret;
257         }
258
259         /* we avoid using strtok and friends due to their nasty
260            interface. This is a little trickier, but much nicer
261            from a C interface point of view */
262         while ((len = strcspn(attrs, " ,")) > 0) {
263                 for (i=0;names[i].name;i++) {
264                         if (strncmp(names[i].name, attrs, len) == 0 &&
265                             names[i].name[len] == 0) {
266                                 ret |= names[i].value;
267                         }
268                 }
269                 attrs += len;
270                 attrs += strspn(attrs, " ,");
271         }
272
273         ldb->alloc_ops.alloc = NULL;
274
275         ldb_free(ldb, ltdb->cache.last_attribute.name);
276
277         ltdb->cache.last_attribute.name = ldb_strdup(ldb, attr_name);
278         ltdb->cache.last_attribute.flags = ret;
279
280         ldb->alloc_ops = alloc;
281         
282         return ret;
283 }