r435: a major upgrade for ldb
[jra/samba/.git] / source4 / lib / ldb / ldb_tdb / ldb_tdb.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 backend
29  *
30  *  Description: core functions for tdb backend
31  *
32  *  Author: Andrew Tridgell
33  */
34
35 #include "includes.h"
36 #include "ldb/ldb_tdb/ldb_tdb.h"
37
38 /*
39   form a TDB_DATA for a record key
40   caller frees
41
42   note that the key for a record can depend on whether the 
43   dn refers to a case sensitive index record or not
44 */
45 struct TDB_DATA ltdb_key(struct ldb_context *ldb, const char *dn)
46 {
47         TDB_DATA key;
48         char *key_str = NULL;
49         char *dn_folded = NULL;
50         const char *prefix = LTDB_INDEX ":";
51         const char *s;
52         int flags;
53
54         /*
55           most DNs are case insensitive. The exception is index DNs for
56           case sensitive attributes
57         */
58         if (strncmp(dn, prefix, strlen(prefix)) == 0 &&
59             (s = strchr(dn+strlen(prefix), ':'))) {
60                 char *attr_name, *attr_name_folded;
61                 attr_name = strndup(dn+strlen(prefix), (s-(dn+strlen(prefix))));
62                 if (!attr_name) {
63                         goto failed;
64                 }
65                 flags = ltdb_attribute_flags(ldb, attr_name);
66                 
67                 if (flags & LTDB_FLAG_CASE_INSENSITIVE) {
68                         dn_folded = ldb_casefold(dn);
69                 } else {
70                         attr_name_folded = ldb_casefold(attr_name);
71                         if (!attr_name_folded) {
72                                 goto failed;
73                         }
74                         asprintf(&dn_folded, "%s:%s:%s",
75                                  prefix, attr_name_folded,
76                                  s+1);
77                         free(attr_name_folded);
78                 }
79                 free(attr_name);
80         } else {
81                 dn_folded = ldb_casefold(dn);
82         }
83
84         if (!dn_folded) {
85                 goto failed;
86         }
87
88         asprintf(&key_str, "DN=%s", dn_folded);
89         free(dn_folded);
90
91         if (!key_str) {
92                 goto failed;
93         }
94
95         key.dptr = key_str;
96         key.dsize = strlen(key_str)+1;
97
98         return key;
99
100 failed:
101         errno = ENOMEM;
102         key.dptr = NULL;
103         key.dsize = 0;
104         return key;
105 }
106
107 /*
108   lock the database for write - currently a single lock is used
109 */
110 static int ltdb_lock(struct ldb_context *ldb)
111 {
112         struct ltdb_private *ltdb = ldb->private_data;
113         TDB_DATA key;
114         int ret;
115
116         key = ltdb_key(ldb, "LDBLOCK");
117         if (!key.dptr) {
118                 return -1;
119         }
120
121         ret = tdb_chainlock(ltdb->tdb, key);
122
123         free(key.dptr);
124
125         return ret;
126 }
127
128 /*
129   unlock the database after a ltdb_lock()
130 */
131 static void ltdb_unlock(struct ldb_context *ldb)
132 {
133         struct ltdb_private *ltdb = ldb->private_data;
134         TDB_DATA key;
135
136         key = ltdb_key(ldb, "LDBLOCK");
137         if (!key.dptr) {
138                 return;
139         }
140
141         tdb_chainunlock(ltdb->tdb, key);
142
143         free(key.dptr);
144 }
145
146
147 /*
148   we've made a modification to a dn - possibly reindex and 
149   update sequence number
150 */
151 static int ltdb_modified(struct ldb_context *ldb, const char *dn)
152 {
153         int ret = 0;
154
155         if (strcmp(dn, LTDB_INDEXLIST) == 0 ||
156             strcmp(dn, LTDB_ATTRIBUTES) == 0) {
157                 ret = ltdb_reindex(ldb);
158         }
159
160         if (ret == 0 &&
161             strcmp(dn, LTDB_BASEINFO) != 0) {
162                 ret = ltdb_increase_sequence_number(ldb);
163         }
164
165         return ret;
166 }
167
168 /*
169   store a record into the db
170 */
171 int ltdb_store(struct ldb_context *ldb, const struct ldb_message *msg, int flgs)
172 {
173         struct ltdb_private *ltdb = ldb->private_data;
174         TDB_DATA tdb_key, tdb_data;
175         int ret;
176
177         tdb_key = ltdb_key(ldb, msg->dn);
178         if (!tdb_key.dptr) {
179                 return -1;
180         }
181
182         ret = ltdb_pack_data(ldb, msg, &tdb_data);
183         if (ret == -1) {
184                 free(tdb_key.dptr);
185                 return -1;
186         }
187
188         ret = tdb_store(ltdb->tdb, tdb_key, tdb_data, flgs);
189         if (ret == -1) {
190                 goto done;
191         }
192         
193         ret = ltdb_index_add(ldb, msg);
194         if (ret == -1) {
195                 tdb_delete(ltdb->tdb, tdb_key);
196         }
197
198 done:
199         free(tdb_key.dptr);
200         free(tdb_data.dptr);
201
202         return ret;
203 }
204
205
206 /*
207   add a record to the database
208 */
209 static int ltdb_add(struct ldb_context *ldb, const struct ldb_message *msg)
210 {
211         int ret;
212
213         if (ltdb_lock(ldb) != 0) {
214                 return -1;
215         }
216
217         if (ltdb_cache_load(ldb) != 0) {
218                 ltdb_unlock(ldb);
219                 return -1;
220         }
221         
222         ret = ltdb_store(ldb, msg, TDB_INSERT);
223
224         if (ret == 0) {
225                 ltdb_modified(ldb, msg->dn);
226         }
227
228         ltdb_unlock(ldb);
229         return ret;
230 }
231
232
233 /*
234   delete a record from the database, not updating indexes (used for deleting
235   index records)
236 */
237 int ltdb_delete_noindex(struct ldb_context *ldb, const char *dn)
238 {
239         struct ltdb_private *ltdb = ldb->private_data;
240         TDB_DATA tdb_key;
241         int ret;
242
243         tdb_key = ltdb_key(ldb, dn);
244         if (!tdb_key.dptr) {
245                 return -1;
246         }
247
248         ret = tdb_delete(ltdb->tdb, tdb_key);
249         free(tdb_key.dptr);
250
251         return ret;
252 }
253
254 /*
255   delete a record from the database
256 */
257 static int ltdb_delete(struct ldb_context *ldb, const char *dn)
258 {
259         int ret;
260         struct ldb_message msg;
261
262         if (ltdb_lock(ldb) != 0) {
263                 return -1;
264         }
265
266         if (ltdb_cache_load(ldb) != 0) {
267                 ltdb_unlock(ldb);
268                 return -1;
269         }
270
271         /* in case any attribute of the message was indexed, we need
272            to fetch the old record */
273         ret = ltdb_search_dn1(ldb, dn, &msg);
274         if (ret != 1) {
275                 /* not finding the old record is an error */
276                 goto failed;
277         }
278
279         ret = ltdb_delete_noindex(ldb, dn);
280         if (ret == -1) {
281                 ltdb_search_dn1_free(ldb, &msg);
282                 goto failed;
283         }
284
285         /* remove any indexed attributes */
286         ret = ltdb_index_del(ldb, &msg);
287
288         ltdb_search_dn1_free(ldb, &msg);
289
290         if (ret == 0) {
291                 ltdb_modified(ldb, dn);
292         }
293
294         ltdb_unlock(ldb);
295         return ret;
296
297 failed:
298         ltdb_unlock(ldb);
299         return -1;
300 }
301
302
303 /*
304   find an element by attribute name. At the moment this does a linear search, it should
305   be re-coded to use a binary search once all places that modify records guarantee
306   sorted order
307
308   return the index of the first matching element if found, otherwise -1
309 */
310 static int find_element(const struct ldb_message *msg, const char *name)
311 {
312         int i;
313         for (i=0;i<msg->num_elements;i++) {
314                 if (ldb_attr_cmp(msg->elements[i].name, name) == 0) {
315                         return i;
316                 }
317         }
318         return -1;
319 }
320
321
322 /*
323   add an element to an existing record. Assumes a elements array that we
324   can call re-alloc on, and assumed that we can re-use the data pointers from the 
325   passed in additional values. Use with care!
326
327   returns 0 on success, -1 on failure (and sets errno)
328 */
329 static int msg_add_element(struct ldb_message *msg, struct ldb_message_element *el)
330 {
331         struct ldb_message_element *e2;
332         int i;
333
334         e2 = realloc_p(msg->elements, struct ldb_message_element, 
335                        msg->num_elements+1);
336         if (!e2) {
337                 errno = ENOMEM;
338                 return -1;
339         }
340
341         msg->elements = e2;
342
343         e2 = &msg->elements[msg->num_elements];
344
345         e2->name = el->name;
346         e2->flags = el->flags;
347         e2->values = NULL;
348         if (el->num_values != 0) {
349                 e2->values = malloc_array_p(struct ldb_val, el->num_values);
350                 if (!e2->values) {
351                         free(e2->name);
352                         errno = ENOMEM;
353                         return -1;
354                 }
355         }
356         for (i=0;i<el->num_values;i++) {
357                 e2->values[i] = el->values[i];
358         }
359         e2->num_values = el->num_values;
360
361         msg->num_elements++;
362
363         return 0;
364 }
365
366 /*
367   delete all elements having a specified attribute name
368 */
369 static int msg_delete_attribute(struct ldb_message *msg, const char *name)
370 {
371         int i, count=0;
372         struct ldb_message_element *el2;
373
374         el2 = malloc_array_p(struct ldb_message_element, msg->num_elements);
375         if (!el2) {
376                 errno = ENOMEM;
377                 return -1;
378         }
379
380         for (i=0;i<msg->num_elements;i++) {
381                 if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
382                         el2[count++] = msg->elements[i];
383                 } else {
384                         if (msg->elements[i].values) free(msg->elements[i].values);
385                 }
386         }
387
388         msg->num_elements = count;
389         if (msg->elements) free(msg->elements);
390         msg->elements = el2;
391
392         return 0;
393 }
394
395 /*
396   delete all elements matching an attribute name/value 
397
398   return 0 on success, -1 on failure
399 */
400 static int msg_delete_element(struct ldb_context *ldb,
401                               struct ldb_message *msg, 
402                               const char *name,
403                               const struct ldb_val *val)
404 {
405         int i;
406         struct ldb_message_element *el;
407
408         i = find_element(msg, name);
409         if (i == -1) {
410                 return -1;
411         }
412
413         el = &msg->elements[i];
414
415         for (i=0;i<el->num_values;i++) {
416                 if (ldb_val_equal(ldb, msg->elements[i].name, &el->values[i], val)) {
417                         if (i<el->num_values-1) {
418                                 memmove(&el->values[i], &el->values[i+1],
419                                         sizeof(el->values[i])*el->num_values-(i+1));
420                         }
421                         el->num_values--;
422                         return 0;
423                 }
424         }
425         
426         return -1;
427 }
428
429
430 /*
431   modify a record - internal interface
432
433   yuck - this is O(n^2). Luckily n is usually small so we probably
434   get away with it, but if we ever have really large attribute lists 
435   then we'll need to look at this again
436 */
437 int ltdb_modify_internal(struct ldb_context *ldb, const struct ldb_message *msg)
438 {
439         struct ltdb_private *ltdb = ldb->private_data;
440         TDB_DATA tdb_key, tdb_data;
441         struct ldb_message msg2;
442         int ret, i, j;
443
444         tdb_key = ltdb_key(ldb, msg->dn);
445         if (!tdb_key.dptr) {
446                 return -1;
447         }
448
449         tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
450         if (!tdb_data.dptr) {
451                 free(tdb_key.dptr);
452                 return -1;
453         }
454
455         ret = ltdb_unpack_data(ldb, &tdb_data, &msg2);
456         if (ret == -1) {
457                 free(tdb_key.dptr);
458                 free(tdb_data.dptr);
459                 return -1;
460         }
461
462         if (!msg2.dn) {
463                 msg2.dn = msg->dn;
464         }
465
466         for (i=0;i<msg->num_elements;i++) {
467                 switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
468
469                 case LDB_FLAG_MOD_ADD:
470                         /* add this element to the message. fail if it
471                            already exists */
472                         ret = find_element(&msg2, msg->elements[i].name);
473                         if (ret != -1) {
474                                 errno = EEXIST;
475                                 goto failed;
476                         }
477                         if (msg_add_element(&msg2, &msg->elements[i]) != 0) {
478                                 goto failed;
479                         }
480                         break;
481
482                 case LDB_FLAG_MOD_REPLACE:
483                         /* replace all elements of this attribute name with the elements
484                            listed */
485                         if (msg_delete_attribute(&msg2, msg->elements[i].name) != 0) {
486                                 goto failed;
487                         }
488                         /* add the replacement element */
489                         if (msg_add_element(&msg2, &msg->elements[i]) != 0) {
490                                 goto failed;
491                         }
492                         break;
493
494                 case LDB_FLAG_MOD_DELETE:
495                         /* we could be being asked to delete all
496                            values or just some values */
497                         if (msg->elements[i].num_values == 0) {
498                                 if (msg_delete_attribute(&msg2, 
499                                                           msg->elements[i].name) != 0) {
500                                         goto failed;
501                                 }
502                                 break;
503                         }
504                         for (j=0;j<msg->elements[i].num_values;j++) {
505                                 if (msg_delete_element(ldb,
506                                                        &msg2, 
507                                                        msg->elements[i].name,
508                                                        &msg->elements[i].values[j]) != 0) {
509                                         goto failed;
510                                 }
511                         }
512                         break;
513                 }
514         }
515
516         /* we've made all the mods - save the modified record back into the database */
517         ret = ltdb_store(ldb, &msg2, TDB_MODIFY);
518
519         free(tdb_key.dptr);
520         free(tdb_data.dptr);
521         ltdb_unpack_data_free(&msg2);
522         return ret;
523
524 failed:
525         free(tdb_key.dptr);
526         free(tdb_data.dptr);
527         ltdb_unpack_data_free(&msg2);
528         return -1;
529 }
530
531 /*
532   modify a record
533 */
534 static int ltdb_modify(struct ldb_context *ldb, const struct ldb_message *msg)
535 {
536         int ret;
537
538         if (ltdb_lock(ldb) != 0) {
539                 return -1;
540         }
541
542         if (ltdb_cache_load(ldb) != 0) {
543                 ltdb_unlock(ldb);
544                 return -1;
545         }
546
547         ret = ltdb_modify_internal(ldb, msg);
548
549         if (ret == 0) {
550                 ltdb_modified(ldb, msg->dn);
551         }
552
553         ltdb_unlock(ldb);
554
555         return ret;
556 }
557
558 /*
559   close database
560 */
561 static int ltdb_close(struct ldb_context *ldb)
562 {
563         struct ltdb_private *ltdb = ldb->private_data;
564         int ret;
565
566         ltdb_cache_free(ldb);
567
568         ret = tdb_close(ltdb->tdb);
569         free(ltdb);
570         free(ldb);
571         return ret;
572 }
573                       
574
575 /*
576   return extended error information
577 */
578 static const char *ltdb_errstring(struct ldb_context *ldb)
579 {
580         struct ltdb_private *ltdb = ldb->private_data;
581         return tdb_errorstr(ltdb->tdb);
582 }
583
584
585 static const struct ldb_backend_ops ltdb_ops = {
586         ltdb_close, 
587         ltdb_search,
588         ltdb_search_free,
589         ltdb_add,
590         ltdb_modify,
591         ltdb_delete,
592         ltdb_errstring
593 };
594
595
596 /*
597   connect to the database
598 */
599 struct ldb_context *ltdb_connect(const char *url, 
600                                  unsigned int flags, 
601                                  const char *options[])
602 {
603         const char *path;
604         int tdb_flags, open_flags;
605         struct ltdb_private *ltdb;
606         TDB_CONTEXT *tdb;
607         struct ldb_context *ldb;
608
609         /* parse the url */
610         if (strncmp(url, "tdb://", 6) != 0) {
611                 errno = EINVAL;
612                 return NULL;
613         }
614
615         path = url+6;
616
617         tdb_flags = TDB_DEFAULT;
618
619         if (flags & LDB_FLG_RDONLY) {
620                 open_flags = O_RDONLY;
621         } else {
622                 open_flags = O_CREAT | O_RDWR;
623         }
624
625         /* note that we use quite a large default hash size */
626         tdb = tdb_open(path, 10000, tdb_flags, open_flags, 0666);
627         if (!tdb) {
628                 return NULL;
629         }
630
631         ltdb = malloc_p(struct ltdb_private);
632         if (!ltdb) {
633                 tdb_close(tdb);
634                 errno = ENOMEM;
635                 return NULL;
636         }
637
638         ltdb->tdb = tdb;
639         ltdb->sequence_number = 0;
640
641         memset(&ltdb->cache, 0, sizeof(ltdb->cache));
642
643         ldb = malloc_p(struct ldb_context);
644         if (!ldb) {
645                 tdb_close(tdb);
646                 free(ltdb);
647                 errno = ENOMEM;
648                 return NULL;
649         }
650
651         ldb->private_data = ltdb;
652         ldb->ops = &ltdb_ops;
653
654         return ldb;
655 }