r11567: Ldb API change patch.
[abartlet/samba.git/.git] / source4 / lib / ldb / ldb_tdb / ldb_search.c
index 922d24b6ebdfcf6df5a7e701331eedf603024812..01a87e00b19665be025cc896fc28844f233bac88 100644 (file)
@@ -34,6 +34,7 @@
 
 #include "includes.h"
 #include "ldb/include/ldb.h"
+#include "ldb/include/ldb_errors.h"
 #include "ldb/include/ldb_private.h"
 #include "ldb/ldb_tdb/ldb_tdb.h"
 
   add one element to a message
 */
 static int msg_add_element(struct ldb_context *ldb, 
-                          struct ldb_message *ret, const struct ldb_message_element *el)
+                          struct ldb_message *ret, 
+                          const struct ldb_message_element *el,
+                          int check_duplicates)
 {
        unsigned int i;
        struct ldb_message_element *e2, *elnew;
 
+       if (check_duplicates && ldb_msg_find_element(ret, el->name)) {
+               /* its already there */
+               return 0;
+       }
+
        e2 = talloc_realloc(ret, ret->elements, struct ldb_message_element, ret->num_elements+1);
        if (!e2) {
                return -1;
@@ -82,6 +90,26 @@ static int msg_add_element(struct ldb_context *ldb,
        return 0;
 }
 
+/*
+  add the special distinguishedName element
+*/
+static int msg_add_distinguished_name(struct ldb_module *module, struct ldb_message *msg)
+{
+       struct ldb_message_element el;
+       struct ldb_val val;
+       int ret;
+
+       el.flags = 0;
+       el.name = "distinguishedName";
+       el.num_values = 1;
+       el.values = &val;
+       val.data = (uint8_t *)ldb_dn_linearize(msg, msg->dn);
+       val.length = strlen((char *)val.data);
+       
+       ret = msg_add_element(module->ldb, msg, &el, 1);
+       return ret;
+}
+
 /*
   add all elements from one message into another
  */
@@ -90,14 +118,20 @@ static int msg_add_all_elements(struct ldb_module *module, struct ldb_message *r
 {
        struct ldb_context *ldb = module->ldb;
        unsigned int i;
+       int check_duplicates = (ret->num_elements != 0);
+
+       if (msg_add_distinguished_name(module, ret) != 0) {
+               return -1;
+       }
 
        for (i=0;i<msg->num_elements;i++) {
                const struct ldb_attrib_handler *h;
                h = ldb_attrib_handler(ldb, msg->elements[i].name);
-               if ((msg->dn[0] != '@') && (h->flags & LDB_ATTR_FLAG_HIDDEN)) {
+               if (h->flags & LDB_ATTR_FLAG_HIDDEN) {
                        continue;
                }
-               if (msg_add_element(ldb, ret, &msg->elements[i]) != 0) {
+               if (msg_add_element(ldb, ret, &msg->elements[i],
+                                   check_duplicates) != 0) {
                        return -1;
                }
        }
@@ -122,7 +156,7 @@ static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module,
                return NULL;
        }
 
-       ret->dn = talloc_strdup(ret, msg->dn);
+       ret->dn = ldb_dn_copy(ret, msg->dn);
        if (!ret->dn) {
                talloc_free(ret);
                return NULL;
@@ -150,27 +184,10 @@ static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module,
                        continue;
                }
 
-               if (ldb_attr_cmp(attrs[i], "dn") == 0 ||
-                   ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
-                       struct ldb_message_element el2;
-                       struct ldb_val val;
-
-                       el2.flags = 0;
-                       el2.name = talloc_strdup(ret, attrs[i]);
-                       if (!el2.name) {
-                               talloc_free(ret);
-                               return NULL;                            
-                       }
-                       el2.num_values = 1;
-                       el2.values = &val;
-                       val.data = ret->dn;
-                       val.length = strlen(ret->dn);
-
-                       if (msg_add_element(ldb, ret, &el2) != 0) {
-                               talloc_free(ret);
-                               return NULL;                            
+               if (ldb_attr_cmp(attrs[i], "distinguishedName") == 0) {
+                       if (msg_add_distinguished_name(module, ret) != 0) {
+                               return NULL;
                        }
-                       talloc_free(discard_const_p(char, el2.name));
                        continue;
                }
 
@@ -178,7 +195,7 @@ static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module,
                if (!el) {
                        continue;
                }
-               if (msg_add_element(ldb, ret, el) != 0) {
+               if (msg_add_element(ldb, ret, el, 1) != 0) {
                        talloc_free(ret);
                        return NULL;                            
                }
@@ -194,7 +211,7 @@ static struct ldb_message *ltdb_pull_attrs(struct ldb_module *module,
 
   return 1 on success, 0 on record-not-found and -1 on error
 */
-int ltdb_search_dn1(struct ldb_module *module, const char *dn, struct ldb_message *msg)
+int ltdb_search_dn1(struct ldb_module *module, const struct ldb_dn *dn, struct ldb_message *msg)
 {
        struct ltdb_private *ltdb = module->private_data;
        int ret;
@@ -231,7 +248,7 @@ int ltdb_search_dn1(struct ldb_module *module, const char *dn, struct ldb_messag
        }
 
        if (!msg->dn) {
-               msg->dn = talloc_strdup(tdb_data2.dptr, dn);
+               msg->dn = ldb_dn_copy(tdb_data2.dptr, dn);
        }
        if (!msg->dn) {
                talloc_free(tdb_data2.dptr);
@@ -241,77 +258,48 @@ int ltdb_search_dn1(struct ldb_module *module, const char *dn, struct ldb_messag
        return 1;
 }
 
+/* the lock key for search locking. Note that this is not a DN, its
+   just an arbitrary key to give to tdb. Also note that as we and
+   using transactions for all write operations and transactions take
+   care of their own locks, we don't need to do any locking anywhere
+   other than in ldb_search() */
+#define LDBLOCK        "INT_LDBLOCK"
 
 /*
-  search the database for a single simple dn
+  lock the database for read - use by ltdb_search
 */
-static int ltdb_search_dn(struct ldb_module *module, const char *dn,
-                         const char * const attrs[], struct ldb_message ***res)
+static int ltdb_lock_read(struct ldb_module *module)
 {
-       struct ldb_context *ldb = module->ldb;
        struct ltdb_private *ltdb = module->private_data;
-       int ret;
-       struct ldb_message *msg, *msg2;
-
-       *res = NULL;
+       TDB_DATA key;
 
-       if (ltdb_lock_read(module) != 0) {
-               return -1;
-       }
-
-       ltdb->last_err_string = NULL;
-
-       if (ltdb_cache_load(module) != 0) {
-               ltdb_unlock_read(module);
-               return -1;
-       }
-
-       *res = talloc_array(ldb, struct ldb_message *, 2);
-       if (! *res) {
-               goto failed;
-       }
-
-       msg = talloc(*res, struct ldb_message);
-       if (msg == NULL) {
-               goto failed;
-       }
-
-       ret = ltdb_search_dn1(module, dn, msg);
-       if (ret != 1) {
-               talloc_free(*res);
-               *res = NULL;
-               ltdb_unlock_read(module);
-               return 0;
-       }
+       key.dptr = discard_const(LDBLOCK);
+       key.dsize = strlen(LDBLOCK);
 
-       msg2 = ltdb_pull_attrs(module, msg, attrs);
-
-       talloc_free(msg);
-       if (!msg2) {
-               goto failed;
-       }
-
-       (*res)[0] = talloc_steal(*res, msg2);
-       (*res)[1] = NULL;
+       return tdb_chainlock_read(ltdb->tdb, key);
+}
 
-       ltdb_unlock_read(module);
+/*
+  unlock the database after a ltdb_lock_read()
+*/
+static int ltdb_unlock_read(struct ldb_module *module)
+{
+       struct ltdb_private *ltdb = module->private_data;
+       TDB_DATA key;
 
-       return 1;
+       key.dptr = discard_const(LDBLOCK);
+       key.dsize = strlen(LDBLOCK);
 
-failed:
-       talloc_free(*res);
-       ltdb_unlock_read(module);
-       return -1;
+       return tdb_chainunlock_read(ltdb->tdb, key);
 }
 
-
 /*
   add a set of attributes from a record to a set of results
   return 0 on success, -1 on failure
 */
 int ltdb_add_attr_results(struct ldb_module *module, struct ldb_message *msg,
                          const char * const attrs[], 
-                         int *count, 
+                         unsigned int *count, 
                          struct ldb_message ***res)
 {
        struct ldb_context *ldb = module->ldb;
@@ -347,12 +335,12 @@ int ltdb_add_attr_results(struct ldb_module *module, struct ldb_message *msg,
 struct ltdb_search_info {
        struct ldb_module *module;
        struct ldb_parse_tree *tree;
-       const char *base;
+       const struct ldb_dn *base;
        enum ldb_scope scope;
        const char * const *attrs;
        struct ldb_message **msgs;
-       int failures;
-       int count;
+       unsigned int failures;
+       unsigned int count;
 };
 
 
@@ -366,7 +354,7 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
        int ret;
 
        if (key.dsize < 4 || 
-           strncmp(key.dptr, "DN=", 3) != 0) {
+           strncmp((char *)key.dptr, "DN=", 3) != 0) {
                return 0;
        }
 
@@ -384,7 +372,11 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
        }
 
        if (!msg->dn) {
-               msg->dn = key.dptr + 3;
+               msg->dn = ldb_dn_explode(msg, (char *)key.dptr + 3);
+               if (msg->dn == NULL) {
+                       talloc_free(msg);
+                       return -1;
+               }
        }
 
        /* see if it matches the given expression */
@@ -411,18 +403,25 @@ static int search_func(struct tdb_context *tdb, TDB_DATA key, TDB_DATA data, voi
   this is the "full search" non-indexed variant
 */
 static int ltdb_search_full(struct ldb_module *module, 
-                           const char *base,
+                           const struct ldb_dn *base,
                            enum ldb_scope scope,
                            struct ldb_parse_tree *tree,
-                           const char * const attrs[], struct ldb_message ***res)
+                           const char * const attrs[], struct ldb_result **res)
 {
        struct ltdb_private *ltdb = module->private_data;
-       int ret, count;
+       struct ldb_result *result;
+       int ret;
        struct ltdb_search_info *sinfo;
 
+       result = talloc(ltdb, struct ldb_result);
+       if (result == NULL) {
+               return LDB_ERR_OTHER;
+       }
+
        sinfo = talloc(ltdb, struct ltdb_search_info);
        if (sinfo == NULL) {
-               return -1;
+               talloc_free(result);
+               return LDB_ERR_OTHER;
        }
 
        sinfo->tree = tree;
@@ -434,19 +433,21 @@ static int ltdb_search_full(struct ldb_module *module,
        sinfo->count = 0;
        sinfo->failures = 0;
 
-       ret = tdb_traverse(ltdb->tdb, search_func, sinfo);
+       ret = tdb_traverse_read(ltdb->tdb, search_func, sinfo);
 
        if (ret == -1) {
+               talloc_free(result);
                talloc_free(sinfo);
                return -1;
        }
 
-       *res = talloc_steal(ltdb, sinfo->msgs);
-       count = sinfo->count;
+       result->msgs = talloc_steal(result, sinfo->msgs);
+       result->count = sinfo->count;
+       *res = result;
 
        talloc_free(sinfo);
 
-       return count;
+       return LDB_SUCCESS;
 }
 
 
@@ -454,27 +455,19 @@ static int ltdb_search_full(struct ldb_module *module,
   search the database with a LDAP-like expression.
   choses a search method
 */
-int ltdb_search_bytree(struct ldb_module *module, const char *base,
+int ltdb_search_bytree(struct ldb_module *module, const struct ldb_dn *base,
                       enum ldb_scope scope, struct ldb_parse_tree *tree,
-                      const char * const attrs[], struct ldb_message ***res)
+                      const char * const attrs[], struct ldb_result **res)
 {
-       struct ltdb_private *ltdb = module->private_data;
        int ret;
 
-       /* it is important that we handle dn queries this way, and not
-          via a full db search, otherwise ldb is horribly slow */
-       if (tree->operation == LDB_OP_EQUALITY &&
-           (ldb_attr_cmp(tree->u.equality.attr, "dn") == 0 ||
-            ldb_attr_cmp(tree->u.equality.attr, "distinguishedName") == 0)) {
-               return ltdb_search_dn(module, tree->u.equality.value.data, attrs, res);
-       }
+       if ((base == NULL || base->comp_num == 0) &&
+           (scope == LDB_SCOPE_BASE || scope == LDB_SCOPE_ONELEVEL)) return -1;
 
        if (ltdb_lock_read(module) != 0) {
                return -1;
        }
 
-       ltdb->last_err_string = NULL;
-
        if (ltdb_cache_load(module) != 0) {
                ltdb_unlock_read(module);
                return -1;
@@ -493,32 +486,3 @@ int ltdb_search_bytree(struct ldb_module *module, const char *base,
 }
 
 
-/*
-  search the database with a LDAP-like expression.
-  choses a search method
-*/
-int ltdb_search(struct ldb_module *module, const char *base,
-               enum ldb_scope scope, const char *expression,
-               const char * const attrs[], struct ldb_message ***res)
-{
-       struct ltdb_private *ltdb = module->private_data;
-       struct ldb_parse_tree *tree;
-       int ret;
-
-       /* check if we are looking for a simple dn */
-       if (scope == LDB_SCOPE_BASE && (expression == NULL || expression[0] == '\0')) {
-               ret = ltdb_search_dn(module, base, attrs, res);
-               return ret;
-       }
-
-       tree = ldb_parse_tree(ltdb, expression);
-       if (tree == NULL) {
-               ltdb->last_err_string = "expression parse failed";
-               return -1;
-       }
-
-       ret = ltdb_search_bytree(module, base, scope, tree, attrs, res);
-       talloc_free(tree);
-       return ret;
-}
-