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