s4:ldb Allow ldb_msg_canonicalize to handle empty elements
[Samba/ekacnet.git] / source4 / lib / ldb / common / ldb_msg.c
blob161a6b1f38334ce80e44bda0baa0784cb2261191
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 3 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, see <http://www.gnu.org/licenses/>.
25 * Name: ldb
27 * Component: ldb message component utility functions
29 * Description: functions for manipulating ldb_message structures
31 * Author: Andrew Tridgell
34 #include "ldb_private.h"
37 create a new ldb_message in a given memory context (NULL for top level)
39 struct ldb_message *ldb_msg_new(void *mem_ctx)
41 return talloc_zero(mem_ctx, struct ldb_message);
45 find an element in a message by attribute name
47 struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg,
48 const char *attr_name)
50 unsigned int i;
51 for (i=0;i<msg->num_elements;i++) {
52 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
53 return &msg->elements[i];
56 return NULL;
60 see if two ldb_val structures contain exactly the same data
61 return 1 for a match, 0 for a mis-match
63 int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
65 if (v1->length != v2->length) return 0;
66 if (v1->data == v2->data) return 1;
67 if (v1->length == 0) return 1;
69 if (memcmp(v1->data, v2->data, v1->length) == 0) {
70 return 1;
73 return 0;
77 find a value in an element
78 assumes case sensitive comparison
80 struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el,
81 struct ldb_val *val)
83 unsigned int i;
84 for (i=0;i<el->num_values;i++) {
85 if (ldb_val_equal_exact(val, &el->values[i])) {
86 return &el->values[i];
89 return NULL;
93 duplicate a ldb_val structure
95 struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
97 struct ldb_val v2;
98 v2.length = v->length;
99 if (v->data == NULL) {
100 v2.data = NULL;
101 return v2;
104 /* the +1 is to cope with buggy C library routines like strndup
105 that look one byte beyond */
106 v2.data = talloc_array(mem_ctx, uint8_t, v->length+1);
107 if (!v2.data) {
108 v2.length = 0;
109 return v2;
112 memcpy(v2.data, v->data, v->length);
113 ((char *)v2.data)[v->length] = 0;
114 return v2;
118 add an empty element to a message
120 int ldb_msg_add_empty( struct ldb_message *msg,
121 const char *attr_name,
122 int flags,
123 struct ldb_message_element **return_el)
125 struct ldb_message_element *els;
127 els = talloc_realloc(msg, msg->elements,
128 struct ldb_message_element, msg->num_elements+1);
129 if (!els) {
130 errno = ENOMEM;
131 return LDB_ERR_OPERATIONS_ERROR;
134 els[msg->num_elements].values = NULL;
135 els[msg->num_elements].num_values = 0;
136 els[msg->num_elements].flags = flags;
137 els[msg->num_elements].name = talloc_strdup(els, attr_name);
138 if (!els[msg->num_elements].name) {
139 errno = ENOMEM;
140 return LDB_ERR_OPERATIONS_ERROR;
143 msg->elements = els;
144 msg->num_elements++;
146 if (return_el) {
147 *return_el = &els[msg->num_elements-1];
150 return LDB_SUCCESS;
154 add an empty element to a message
156 int ldb_msg_add(struct ldb_message *msg,
157 const struct ldb_message_element *el,
158 int flags)
160 /* We have to copy this, just in case *el is a pointer into
161 * what ldb_msg_add_empty() is about to realloc() */
162 struct ldb_message_element el_copy = *el;
163 if (ldb_msg_add_empty(msg, el->name, flags, NULL) != 0) {
164 return LDB_ERR_OPERATIONS_ERROR;
167 msg->elements[msg->num_elements-1] = el_copy;
168 msg->elements[msg->num_elements-1].flags = flags;
170 return LDB_SUCCESS;
174 add a value to a message
176 int ldb_msg_add_value(struct ldb_message *msg,
177 const char *attr_name,
178 const struct ldb_val *val,
179 struct ldb_message_element **return_el)
181 struct ldb_message_element *el;
182 struct ldb_val *vals;
183 int ret;
185 el = ldb_msg_find_element(msg, attr_name);
186 if (!el) {
187 ret = ldb_msg_add_empty(msg, attr_name, 0, &el);
188 if (ret != LDB_SUCCESS) {
189 return ret;
193 vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
194 if (!vals) {
195 errno = ENOMEM;
196 return LDB_ERR_OPERATIONS_ERROR;
198 el->values = vals;
199 el->values[el->num_values] = *val;
200 el->num_values++;
202 if (return_el) {
203 *return_el = el;
206 return LDB_SUCCESS;
211 add a value to a message, stealing it into the 'right' place
213 int ldb_msg_add_steal_value(struct ldb_message *msg,
214 const char *attr_name,
215 struct ldb_val *val)
217 int ret;
218 struct ldb_message_element *el;
220 ret = ldb_msg_add_value(msg, attr_name, val, &el);
221 if (ret == LDB_SUCCESS) {
222 talloc_steal(el->values, val->data);
224 return ret;
229 add a string element to a message
231 int ldb_msg_add_string(struct ldb_message *msg,
232 const char *attr_name, const char *str)
234 struct ldb_val val;
236 val.data = discard_const_p(uint8_t, str);
237 val.length = strlen(str);
239 if (val.length == 0) {
240 /* allow empty strings as non-existant attributes */
241 return LDB_SUCCESS;
244 return ldb_msg_add_value(msg, attr_name, &val, NULL);
248 add a string element to a message, stealing it into the 'right' place
250 int ldb_msg_add_steal_string(struct ldb_message *msg,
251 const char *attr_name, char *str)
253 struct ldb_val val;
255 val.data = (uint8_t *)str;
256 val.length = strlen(str);
258 return ldb_msg_add_steal_value(msg, attr_name, &val);
262 add a printf formatted element to a message
264 int ldb_msg_add_fmt(struct ldb_message *msg,
265 const char *attr_name, const char *fmt, ...)
267 struct ldb_val val;
268 va_list ap;
269 char *str;
271 va_start(ap, fmt);
272 str = talloc_vasprintf(msg, fmt, ap);
273 va_end(ap);
275 if (str == NULL) return LDB_ERR_OPERATIONS_ERROR;
277 val.data = (uint8_t *)str;
278 val.length = strlen(str);
280 return ldb_msg_add_steal_value(msg, attr_name, &val);
284 compare two ldb_message_element structures
285 assumes case senistive comparison
287 int ldb_msg_element_compare(struct ldb_message_element *el1,
288 struct ldb_message_element *el2)
290 unsigned int i;
292 if (el1->num_values != el2->num_values) {
293 return el1->num_values - el2->num_values;
296 for (i=0;i<el1->num_values;i++) {
297 if (!ldb_msg_find_val(el2, &el1->values[i])) {
298 return -1;
302 return 0;
306 compare two ldb_message_element structures
307 comparing by element name
309 int ldb_msg_element_compare_name(struct ldb_message_element *el1,
310 struct ldb_message_element *el2)
312 return ldb_attr_cmp(el1->name, el2->name);
316 convenience functions to return common types from a message
317 these return the first value if the attribute is multi-valued
319 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg,
320 const char *attr_name)
322 struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
323 if (!el || el->num_values == 0) {
324 return NULL;
326 return &el->values[0];
329 int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
330 const char *attr_name,
331 int default_value)
333 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
334 if (!v || !v->data) {
335 return default_value;
337 return strtol((const char *)v->data, NULL, 0);
340 unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
341 const char *attr_name,
342 unsigned int default_value)
344 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
345 if (!v || !v->data) {
346 return default_value;
348 return strtoul((const char *)v->data, NULL, 0);
351 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
352 const char *attr_name,
353 int64_t default_value)
355 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
356 if (!v || !v->data) {
357 return default_value;
359 return strtoll((const char *)v->data, NULL, 0);
362 uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
363 const char *attr_name,
364 uint64_t default_value)
366 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
367 if (!v || !v->data) {
368 return default_value;
370 return strtoull((const char *)v->data, NULL, 0);
373 double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
374 const char *attr_name,
375 double default_value)
377 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
378 if (!v || !v->data) {
379 return default_value;
381 return strtod((const char *)v->data, NULL);
384 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg,
385 const char *attr_name,
386 int default_value)
388 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
389 if (!v || !v->data) {
390 return default_value;
392 if (v->length == 5 && strncasecmp((const char *)v->data, "FALSE", 5) == 0) {
393 return 0;
395 if (v->length == 4 && strncasecmp((const char *)v->data, "TRUE", 4) == 0) {
396 return 1;
398 return default_value;
401 const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
402 const char *attr_name,
403 const char *default_value)
405 const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
406 if (!v || !v->data) {
407 return default_value;
409 return (const char *)v->data;
412 struct ldb_dn *ldb_msg_find_attr_as_dn(struct ldb_context *ldb,
413 void *mem_ctx,
414 const struct ldb_message *msg,
415 const char *attr_name)
417 struct ldb_dn *res_dn;
418 const struct ldb_val *v;
420 v = ldb_msg_find_ldb_val(msg, attr_name);
421 if (!v || !v->data) {
422 return NULL;
424 res_dn = ldb_dn_from_ldb_val(mem_ctx, ldb, v);
425 if ( ! ldb_dn_validate(res_dn)) {
426 talloc_free(res_dn);
427 return NULL;
429 return res_dn;
433 sort the elements of a message by name
435 void ldb_msg_sort_elements(struct ldb_message *msg)
437 qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
438 (comparison_fn_t)ldb_msg_element_compare_name);
442 shallow copy a message - copying only the elements array so that the caller
443 can safely add new elements without changing the message
445 struct ldb_message *ldb_msg_copy_shallow(TALLOC_CTX *mem_ctx,
446 const struct ldb_message *msg)
448 struct ldb_message *msg2;
449 int i;
451 msg2 = talloc(mem_ctx, struct ldb_message);
452 if (msg2 == NULL) return NULL;
454 *msg2 = *msg;
456 msg2->elements = talloc_array(msg2, struct ldb_message_element,
457 msg2->num_elements);
458 if (msg2->elements == NULL) goto failed;
460 for (i=0;i<msg2->num_elements;i++) {
461 msg2->elements[i] = msg->elements[i];
464 return msg2;
466 failed:
467 talloc_free(msg2);
468 return NULL;
473 copy a message, allocating new memory for all parts
475 struct ldb_message *ldb_msg_copy(TALLOC_CTX *mem_ctx,
476 const struct ldb_message *msg)
478 struct ldb_message *msg2;
479 int i, j;
481 msg2 = ldb_msg_copy_shallow(mem_ctx, msg);
482 if (msg2 == NULL) return NULL;
484 msg2->dn = ldb_dn_copy(msg2, msg2->dn);
485 if (msg2->dn == NULL) goto failed;
487 for (i=0;i<msg2->num_elements;i++) {
488 struct ldb_message_element *el = &msg2->elements[i];
489 struct ldb_val *values = el->values;
490 el->name = talloc_strdup(msg2->elements, el->name);
491 if (el->name == NULL) goto failed;
492 el->values = talloc_array(msg2->elements, struct ldb_val, el->num_values);
493 for (j=0;j<el->num_values;j++) {
494 el->values[j] = ldb_val_dup(el->values, &values[j]);
495 if (el->values[j].data == NULL && values[j].length != 0) {
496 goto failed;
501 return msg2;
503 failed:
504 talloc_free(msg2);
505 return NULL;
510 canonicalise a message, merging elements of the same name
512 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb,
513 const struct ldb_message *msg)
515 int i;
516 struct ldb_message *msg2;
518 msg2 = ldb_msg_copy(ldb, msg);
519 if (msg2 == NULL) return NULL;
521 ldb_msg_sort_elements(msg2);
523 for (i=1;i<msg2->num_elements;i++) {
524 struct ldb_message_element *el1 = &msg2->elements[i-1];
525 struct ldb_message_element *el2 = &msg2->elements[i];
526 if (ldb_msg_element_compare_name(el1, el2) == 0) {
527 el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val,
528 el1->num_values + el2->num_values);
529 if (el1->num_values + el2->num_values > 0 && el1->values == NULL) {
530 return NULL;
532 memcpy(el1->values + el1->num_values,
533 el2->values,
534 sizeof(struct ldb_val) * el2->num_values);
535 el1->num_values += el2->num_values;
536 talloc_free(discard_const_p(char, el2->name));
537 if (i+1<msg2->num_elements) {
538 memmove(el2, el2+1, sizeof(struct ldb_message_element) *
539 (msg2->num_elements - (i+1)));
541 msg2->num_elements--;
542 i--;
546 return msg2;
551 return a ldb_message representing the differences between msg1 and msg2. If you
552 then use this in a ldb_modify() call it can be used to save edits to a message
554 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb,
555 struct ldb_message *msg1,
556 struct ldb_message *msg2)
558 struct ldb_message *mod;
559 struct ldb_message_element *el;
560 unsigned int i;
562 mod = ldb_msg_new(ldb);
563 if (mod == NULL) {
564 return NULL;
567 mod->dn = msg1->dn;
568 mod->num_elements = 0;
569 mod->elements = NULL;
571 msg2 = ldb_msg_canonicalize(ldb, msg2);
572 if (msg2 == NULL) {
573 talloc_free(mod);
574 return NULL;
577 /* look in msg2 to find elements that need to be added
578 or modified */
579 for (i=0;i<msg2->num_elements;i++) {
580 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
582 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
583 continue;
586 if (ldb_msg_add(mod,
587 &msg2->elements[i],
588 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != LDB_SUCCESS) {
589 talloc_free(mod);
590 return NULL;
594 /* look in msg1 to find elements that need to be deleted */
595 for (i=0;i<msg1->num_elements;i++) {
596 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
597 if (el == NULL) {
598 if (ldb_msg_add_empty(mod,
599 msg1->elements[i].name,
600 LDB_FLAG_MOD_DELETE, NULL) != LDB_SUCCESS) {
601 talloc_free(mod);
602 return NULL;
607 return mod;
610 int ldb_msg_sanity_check(struct ldb_context *ldb,
611 const struct ldb_message *msg)
613 int i, j;
615 /* basic check on DN */
616 if (msg->dn == NULL) {
617 /* TODO: return also an error string */
618 ldb_set_errstring(ldb, "ldb message lacks a DN!");
619 return LDB_ERR_INVALID_DN_SYNTAX;
622 /* basic syntax checks */
623 for (i = 0; i < msg->num_elements; i++) {
624 for (j = 0; j < msg->elements[i].num_values; j++) {
625 if (msg->elements[i].values[j].length == 0) {
626 TALLOC_CTX *mem_ctx = talloc_new(ldb);
627 /* an attribute cannot be empty */
628 /* TODO: return also an error string */
629 ldb_asprintf_errstring(ldb, "Element %s has empty attribute in ldb message (%s)!",
630 msg->elements[i].name,
631 ldb_dn_get_linearized(msg->dn));
632 talloc_free(mem_ctx);
633 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
638 return LDB_SUCCESS;
645 copy an attribute list. This only copies the array, not the elements
646 (ie. the elements are left as the same pointers)
648 const char **ldb_attr_list_copy(TALLOC_CTX *mem_ctx, const char * const *attrs)
650 const char **ret;
651 int i;
652 for (i=0;attrs && attrs[i];i++) /* noop */ ;
653 ret = talloc_array(mem_ctx, const char *, i+1);
654 if (ret == NULL) {
655 return NULL;
657 for (i=0;attrs && attrs[i];i++) {
658 ret[i] = attrs[i];
660 ret[i] = attrs[i];
661 return ret;
666 copy an attribute list. This only copies the array, not the elements
667 (ie. the elements are left as the same pointers). The new attribute is added to the list.
669 const char **ldb_attr_list_copy_add(TALLOC_CTX *mem_ctx, const char * const *attrs, const char *new_attr)
671 const char **ret;
672 int i;
673 bool found = false;
674 for (i=0;attrs && attrs[i];i++) {
675 if (ldb_attr_cmp(attrs[i], new_attr) == 0) {
676 found = true;
679 if (found) {
680 return ldb_attr_list_copy(mem_ctx, attrs);
682 ret = talloc_array(mem_ctx, const char *, i+2);
683 if (ret == NULL) {
684 return NULL;
686 for (i=0;attrs && attrs[i];i++) {
687 ret[i] = attrs[i];
689 ret[i] = new_attr;
690 ret[i+1] = NULL;
691 return ret;
696 return 1 if an attribute is in a list of attributes, or 0 otherwise
698 int ldb_attr_in_list(const char * const *attrs, const char *attr)
700 int i;
701 for (i=0;attrs && attrs[i];i++) {
702 if (ldb_attr_cmp(attrs[i], attr) == 0) {
703 return 1;
706 return 0;
711 rename the specified attribute in a search result
713 int ldb_msg_rename_attr(struct ldb_message *msg, const char *attr, const char *replace)
715 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
716 if (el == NULL) {
717 return LDB_SUCCESS;
719 el->name = talloc_strdup(msg->elements, replace);
720 if (el->name == NULL) {
721 return LDB_ERR_OPERATIONS_ERROR;
723 return LDB_SUCCESS;
728 copy the specified attribute in a search result to a new attribute
730 int ldb_msg_copy_attr(struct ldb_message *msg, const char *attr, const char *replace)
732 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
733 if (el == NULL) {
734 return LDB_SUCCESS;
736 if (ldb_msg_add(msg, el, 0) != 0) {
737 return LDB_ERR_OPERATIONS_ERROR;
739 return ldb_msg_rename_attr(msg, attr, replace);
743 remove the specified element in a search result
745 void ldb_msg_remove_element(struct ldb_message *msg, struct ldb_message_element *el)
747 int n = (el - msg->elements);
748 if (n >= msg->num_elements) {
749 /* should we abort() here? */
750 return;
752 if (n != msg->num_elements-1) {
753 memmove(el, el+1, ((msg->num_elements-1) - n)*sizeof(*el));
755 msg->num_elements--;
760 remove the specified attribute in a search result
762 void ldb_msg_remove_attr(struct ldb_message *msg, const char *attr)
764 struct ldb_message_element *el = ldb_msg_find_element(msg, attr);
765 if (el) {
766 ldb_msg_remove_element(msg, el);
771 return a LDAP formatted GeneralizedTime string
773 char *ldb_timestring(TALLOC_CTX *mem_ctx, time_t t)
775 struct tm *tm = gmtime(&t);
776 char *ts;
777 int r;
779 if (!tm) {
780 return NULL;
783 /* we now excatly how long this string will be */
784 ts = talloc_array(mem_ctx, char, 18);
786 /* formatted like: 20040408072012.0Z */
787 r = snprintf(ts, 18,
788 "%04u%02u%02u%02u%02u%02u.0Z",
789 tm->tm_year+1900, tm->tm_mon+1,
790 tm->tm_mday, tm->tm_hour, tm->tm_min,
791 tm->tm_sec);
793 if (r != 17) {
794 talloc_free(ts);
795 return NULL;
798 return ts;
802 convert a LDAP GeneralizedTime string to a time_t. Return 0 if unable to convert
804 time_t ldb_string_to_time(const char *s)
806 struct tm tm;
808 if (s == NULL) return 0;
810 memset(&tm, 0, sizeof(tm));
811 if (sscanf(s, "%04u%02u%02u%02u%02u%02u",
812 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
813 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
814 return 0;
816 tm.tm_year -= 1900;
817 tm.tm_mon -= 1;
819 return timegm(&tm);
823 return a LDAP formatted UTCTime string
825 char *ldb_timestring_utc(TALLOC_CTX *mem_ctx, time_t t)
827 struct tm *tm = gmtime(&t);
828 char *ts;
829 int r;
831 if (!tm) {
832 return NULL;
835 /* we now excatly how long this string will be */
836 ts = talloc_array(mem_ctx, char, 14);
838 /* formatted like: 20040408072012.0Z => 040408072012Z */
839 r = snprintf(ts, 14,
840 "%02u%02u%02u%02u%02u%02uZ",
841 (tm->tm_year+1900)%100, tm->tm_mon+1,
842 tm->tm_mday, tm->tm_hour, tm->tm_min,
843 tm->tm_sec);
845 if (r != 13) {
846 talloc_free(ts);
847 return NULL;
850 return ts;
854 convert a LDAP UTCTime string to a time_t. Return 0 if unable to convert
856 time_t ldb_string_utc_to_time(const char *s)
858 struct tm tm;
860 if (s == NULL) return 0;
862 memset(&tm, 0, sizeof(tm));
863 if (sscanf(s, "%02u%02u%02u%02u%02u%02u",
864 &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
865 &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
866 return 0;
868 if (tm.tm_year < 50) {
869 tm.tm_year += 100;
871 tm.tm_mon -= 1;
873 return timegm(&tm);
878 dump a set of results to a file. Useful from within gdb
880 void ldb_dump_results(struct ldb_context *ldb, struct ldb_result *result, FILE *f)
882 int i;
884 for (i = 0; i < result->count; i++) {
885 struct ldb_ldif ldif;
886 fprintf(f, "# record %d\n", i+1);
887 ldif.changetype = LDB_CHANGETYPE_NONE;
888 ldif.msg = result->msgs[i];
889 ldb_ldif_write_file(ldb, f, &ldif);
894 checks for a string attribute. Returns "1" on match and otherwise "0".
896 int ldb_msg_check_string_attribute(const struct ldb_message *msg,
897 const char *name, const char *value)
899 struct ldb_message_element *el;
900 struct ldb_val val;
902 el = ldb_msg_find_element(msg, name);
903 if (el == NULL) {
904 return 0;
907 val.data = discard_const_p(uint8_t, value);
908 val.length = strlen(value);
910 if (ldb_msg_find_val(el, &val)) {
911 return 1;
914 return 0;