r141: A number of changes to get things working on FreeBSD and reduce the breakage
[Samba.git] / source4 / lib / ldb / ldb_tdb / ldb_tdb.c
blobec90eec03ff161b9e5a7265ac92345b160a8f0dc
1 /*
2 ldb database library
4 Copyright (C) Andrew Tridgell 2004
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
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.
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.
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
26 * Name: ldb
28 * Component: ldb tdb backend
30 * Description: core functions for tdb backend
32 * Author: Andrew Tridgell
35 #include "includes.h"
36 #include "ldb_tdb.h"
39 form a TDB_DATA for a record key
40 caller frees
42 struct TDB_DATA ltdb_key(const char *dn)
44 TDB_DATA key;
45 char *key_str = NULL;
47 asprintf(&key_str, "DN=%s", dn);
48 if (!key_str) {
49 errno = ENOMEM;
50 key.dptr = NULL;
51 key.dsize = 0;
52 return key;
55 key.dptr = key_str;
56 key.dsize = strlen(key_str)+1;
58 return key;
62 lock the database for write - currently a single lock is used
64 static int ltdb_lock(struct ldb_context *ldb)
66 struct ltdb_private *ltdb = ldb->private;
67 TDB_DATA key;
68 int ret;
70 key = ltdb_key("LDBLOCK");
71 if (!key.dptr) {
72 return -1;
75 ret = tdb_chainlock(ltdb->tdb, key);
77 free(key.dptr);
79 return ret;
83 unlock the database after a ltdb_lock()
85 static void ltdb_unlock(struct ldb_context *ldb)
87 struct ltdb_private *ltdb = ldb->private;
88 TDB_DATA key;
90 key = ltdb_key("LDBLOCK");
91 if (!key.dptr) {
92 return;
95 tdb_chainunlock(ltdb->tdb, key);
97 free(key.dptr);
101 store a record into the db
103 int ltdb_store(struct ldb_context *ldb, const struct ldb_message *msg, int flgs)
105 struct ltdb_private *ltdb = ldb->private;
106 TDB_DATA tdb_key, tdb_data;
107 int ret;
109 tdb_key = ltdb_key(msg->dn);
110 if (!tdb_key.dptr) {
111 return -1;
114 ret = ltdb_pack_data(ldb, msg, &tdb_data);
115 if (ret == -1) {
116 free(tdb_key.dptr);
117 return -1;
120 ret = tdb_store(ltdb->tdb, tdb_key, tdb_data, flgs);
121 if (ret == -1) {
122 goto done;
125 ret = ltdb_index_add(ldb, msg);
126 if (ret == -1) {
127 tdb_delete(ltdb->tdb, tdb_key);
130 done:
131 free(tdb_key.dptr);
132 free(tdb_data.dptr);
134 return ret;
139 add a record to the database
141 static int ltdb_add(struct ldb_context *ldb, const struct ldb_message *msg)
143 int ret;
145 if (ltdb_lock(ldb) != 0) {
146 return -1;
149 ret = ltdb_store(ldb, msg, TDB_INSERT);
151 ltdb_unlock(ldb);
153 return ret;
158 delete a record from the database, not updating indexes (used for deleting
159 index records)
161 int ltdb_delete_noindex(struct ldb_context *ldb, const char *dn)
163 struct ltdb_private *ltdb = ldb->private;
164 TDB_DATA tdb_key;
165 int ret;
167 tdb_key = ltdb_key(dn);
168 if (!tdb_key.dptr) {
169 return -1;
172 ret = tdb_delete(ltdb->tdb, tdb_key);
173 free(tdb_key.dptr);
175 return ret;
179 delete a record from the database
181 static int ltdb_delete(struct ldb_context *ldb, const char *dn)
183 int ret;
184 struct ldb_message msg;
186 if (ltdb_lock(ldb) != 0) {
187 return -1;
190 /* in case any attribute of the message was indexed, we need
191 to fetch the old record */
192 ret = ltdb_search_dn1(ldb, dn, &msg);
193 if (ret != 1) {
194 /* not finding the old record is an error */
195 goto failed;
198 ret = ltdb_delete_noindex(ldb, dn);
199 if (ret == -1) {
200 ltdb_search_dn1_free(ldb, &msg);
201 goto failed;
204 /* remove any indexed attributes */
205 ret = ltdb_index_del(ldb, &msg);
207 ltdb_search_dn1_free(ldb, &msg);
209 ltdb_unlock(ldb);
210 return ret;
212 failed:
213 ltdb_unlock(ldb);
214 return -1;
219 find an element by attribute name. At the moment this does a linear search, it should
220 be re-coded to use a binary search once all places that modify records guarantee
221 sorted order
223 return the index of the first matching element if found, otherwise -1
225 static int find_element(const struct ldb_message *msg, const char *name)
227 int i;
228 for (i=0;i<msg->num_elements;i++) {
229 if (strcmp(msg->elements[i].name, name) == 0) {
230 return i;
233 return -1;
238 add an element to an existing record. Assumes a elements array that we
239 can call re-alloc on, and assumed that we can re-use the data pointers from the
240 passed in additional values. Use with care!
242 returns 0 on success, -1 on failure (and sets errno)
244 static int msg_add_element(struct ldb_message *msg, struct ldb_message_element *el)
246 struct ldb_message_element *e2;
247 int i;
249 e2 = realloc_p(msg->elements, struct ldb_message_element,
250 msg->num_elements+1);
251 if (!e2) {
252 errno = ENOMEM;
253 return -1;
256 msg->elements = e2;
258 e2 = &msg->elements[msg->num_elements];
260 e2->name = el->name;
261 e2->flags = el->flags;
262 e2->values = NULL;
263 if (el->num_values != 0) {
264 e2->values = malloc_array_p(struct ldb_val, el->num_values);
265 if (!e2->values) {
266 free(e2->name);
267 errno = ENOMEM;
268 return -1;
271 for (i=0;i<el->num_values;i++) {
272 e2->values[i] = el->values[i];
274 e2->num_values = el->num_values;
276 msg->num_elements++;
278 return 0;
282 delete all elements having a specified attribute name
284 static int msg_delete_attribute(struct ldb_message *msg, const char *name)
286 int i, count=0;
287 struct ldb_message_element *el2;
289 el2 = malloc_array_p(struct ldb_message_element, msg->num_elements);
290 if (!el2) {
291 errno = ENOMEM;
292 return -1;
295 for (i=0;i<msg->num_elements;i++) {
296 if (strcmp(msg->elements[i].name, name) != 0) {
297 el2[count++] = msg->elements[i];
298 } else {
299 if (msg->elements[i].values) free(msg->elements[i].values);
303 msg->num_elements = count;
304 if (msg->elements) free(msg->elements);
305 msg->elements = el2;
307 return 0;
311 delete all elements matching an attribute name/value
313 return 0 on success, -1 on failure
315 static int msg_delete_element(struct ldb_message *msg,
316 const char *name,
317 const struct ldb_val *val)
319 int i;
320 struct ldb_message_element *el;
322 i = find_element(msg, name);
323 if (i == -1) {
324 return -1;
327 el = &msg->elements[i];
329 for (i=0;i<el->num_values;i++) {
330 if (ldb_val_equal(&el->values[i], val)) {
331 if (i<el->num_values-1) {
332 memmove(&el->values[i], &el->values[i+1],
333 sizeof(el->values[i])*el->num_values-(i+1));
335 el->num_values--;
336 return 0;
340 return -1;
344 modify a record
346 yuck - this is O(n^2). Luckily n is usually small so we probably
347 get away with it, but if we ever have really large attribute lists
348 then we'll need to look at this again
350 static int ltdb_modify(struct ldb_context *ldb, const struct ldb_message *msg)
352 struct ltdb_private *ltdb = ldb->private;
353 TDB_DATA tdb_key, tdb_data;
354 struct ldb_message msg2;
355 int ret, i, j;
357 if (ltdb_lock(ldb) != 0) {
358 return -1;
361 tdb_key = ltdb_key(msg->dn);
362 if (!tdb_key.dptr) {
363 goto unlock_fail;
366 tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
367 if (!tdb_data.dptr) {
368 free(tdb_key.dptr);
369 goto unlock_fail;
372 ret = ltdb_unpack_data(ldb, &tdb_data, &msg2);
373 if (ret == -1) {
374 free(tdb_key.dptr);
375 free(tdb_data.dptr);
376 goto unlock_fail;
379 msg2.dn = msg->dn;
381 for (i=0;i<msg->num_elements;i++) {
382 switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
384 case LDB_FLAG_MOD_ADD:
385 /* add this element to the message. fail if it
386 already exists */
387 ret = find_element(&msg2, msg->elements[i].name);
388 if (ret != -1) {
389 errno = EEXIST;
390 goto failed;
392 if (msg_add_element(&msg2, &msg->elements[i]) != 0) {
393 goto failed;
395 break;
397 case LDB_FLAG_MOD_REPLACE:
398 /* replace all elements of this attribute name with the elements
399 listed */
400 if (msg_delete_attribute(&msg2, msg->elements[i].name) != 0) {
401 goto failed;
403 /* add the replacement element */
404 if (msg_add_element(&msg2, &msg->elements[i]) != 0) {
405 goto failed;
407 break;
409 case LDB_FLAG_MOD_DELETE:
410 /* we could be being asked to delete all
411 values or just some values */
412 if (msg->elements[i].num_values == 0) {
413 if (msg_delete_attribute(&msg2,
414 msg->elements[i].name) != 0) {
415 goto failed;
417 break;
419 for (j=0;j<msg->elements[i].num_values;j++) {
420 if (msg_delete_element(&msg2,
421 msg->elements[i].name,
422 &msg->elements[i].values[j]) != 0) {
423 goto failed;
426 break;
430 /* we've made all the mods - save the modified record back into the database */
431 ret = ltdb_store(ldb, &msg2, TDB_MODIFY);
433 free(tdb_key.dptr);
434 free(tdb_data.dptr);
435 ltdb_unpack_data_free(&msg2);
436 ltdb_unlock(ldb);
438 return ret;
440 failed:
441 free(tdb_key.dptr);
442 free(tdb_data.dptr);
443 ltdb_unpack_data_free(&msg2);
445 unlock_fail:
446 ltdb_unlock(ldb);
448 return -1;
452 close database
454 static int ltdb_close(struct ldb_context *ldb)
456 struct ltdb_private *ltdb = ldb->private;
457 int ret;
458 ret = tdb_close(ltdb->tdb);
459 free(ltdb);
460 free(ldb);
461 return ret;
466 return extended error information
468 static const char *ltdb_errstring(struct ldb_context *ldb)
470 struct ltdb_private *ltdb = ldb->private;
471 return tdb_errorstr(ltdb->tdb);
475 static const struct ldb_backend_ops ltdb_ops = {
476 ltdb_close,
477 ltdb_search,
478 ltdb_search_free,
479 ltdb_add,
480 ltdb_modify,
481 ltdb_delete,
482 ltdb_errstring
487 connect to the database
489 struct ldb_context *ltdb_connect(const char *url,
490 unsigned int flags,
491 const char *options[])
493 const char *path;
494 int tdb_flags, open_flags;
495 struct ltdb_private *ltdb;
496 TDB_CONTEXT *tdb;
497 struct ldb_context *ldb;
499 /* parse the url */
500 if (strncmp(url, "tdb://", 6) != 0) {
501 errno = EINVAL;
502 return NULL;
505 path = url+6;
507 tdb_flags = TDB_DEFAULT;
509 if (flags & LDB_FLG_RDONLY) {
510 open_flags = O_RDONLY;
511 } else {
512 open_flags = O_CREAT | O_RDWR;
515 tdb = tdb_open(path, 0, tdb_flags, open_flags, 0666);
516 if (!tdb) {
517 return NULL;
520 ltdb = malloc_p(struct ltdb_private);
521 if (!ltdb) {
522 tdb_close(tdb);
523 errno = ENOMEM;
524 return NULL;
527 ltdb->tdb = tdb;
530 ldb = malloc_p(struct ldb_context);
531 if (!ldb) {
532 tdb_close(tdb);
533 free(ltdb);
534 errno = ENOMEM;
535 return NULL;
538 ldb->private = ltdb;
539 ldb->ops = &ltdb_ops;
541 return ldb;