r7527: - added a ldb_search_bytree() interface, which takes a ldb_parse_tree
[jelmer/samba4-debian.git] / source / lib / ldb / common / ldb_msg.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 message component utility functions
29  *
30  *  Description: functions for manipulating ldb_message structures
31  *
32  *  Author: Andrew Tridgell
33  */
34
35 #include "includes.h"
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_private.h"
38
39 /*
40   create a new ldb_message in a given memory context (NULL for top level)
41 */
42 struct ldb_message *ldb_msg_new(void *mem_ctx)
43 {
44         return talloc_zero(mem_ctx, struct ldb_message);
45 }
46
47 /*
48   find an element in a message by attribute name
49 */
50 struct ldb_message_element *ldb_msg_find_element(const struct ldb_message *msg, 
51                                                  const char *attr_name)
52 {
53         unsigned int i;
54         for (i=0;i<msg->num_elements;i++) {
55                 if (ldb_attr_cmp(msg->elements[i].name, attr_name) == 0) {
56                         return &msg->elements[i];
57                 }
58         }
59         return NULL;
60 }
61
62 /*
63   see if two ldb_val structures contain exactly the same data
64   return 1 for a match, 0 for a mis-match
65 */
66 int ldb_val_equal_exact(const struct ldb_val *v1, const struct ldb_val *v2)
67 {
68         if (v1->length != v2->length) return 0;
69
70         if (v1->length == 0) return 1;
71
72         if (memcmp(v1->data, v2->data, v1->length) == 0) {
73                 return 1;
74         }
75
76         return 0;
77 }
78
79 /*
80   find a value in an element
81   assumes case sensitive comparison
82 */
83 struct ldb_val *ldb_msg_find_val(const struct ldb_message_element *el, 
84                                  struct ldb_val *val)
85 {
86         unsigned int i;
87         for (i=0;i<el->num_values;i++) {
88                 if (ldb_val_equal_exact(val, &el->values[i])) {
89                         return &el->values[i];
90                 }
91         }
92         return NULL;
93 }
94
95 /*
96   duplicate a ldb_val structure
97 */
98 struct ldb_val ldb_val_dup(void *mem_ctx, const struct ldb_val *v)
99 {
100         struct ldb_val v2;
101         v2.length = v->length;
102         if (v->length == 0) {
103                 v2.data = NULL;
104                 return v2;
105         }
106
107         /* the +1 is to cope with buggy C library routines like strndup
108            that look one byte beyond */
109         v2.data = talloc_array(mem_ctx, char, v->length+1);
110         if (!v2.data) {
111                 v2.length = 0;
112                 return v2;
113         }
114
115         memcpy(v2.data, v->data, v->length);
116         ((char *)v2.data)[v->length] = 0;
117         return v2;
118 }
119
120 /*
121   add an empty element to a message
122 */
123 int ldb_msg_add_empty(struct ldb_context *ldb,
124                       struct ldb_message *msg, const char *attr_name, int flags)
125 {
126         struct ldb_message_element *els;
127
128         els = talloc_realloc(msg, msg->elements, 
129                                struct ldb_message_element, msg->num_elements+1);
130         if (!els) {
131                 errno = ENOMEM;
132                 return -1;
133         }
134
135         els[msg->num_elements].values = NULL;
136         els[msg->num_elements].num_values = 0;
137         els[msg->num_elements].flags = flags;
138         els[msg->num_elements].name = talloc_strdup(els, attr_name);
139         if (!els[msg->num_elements].name) {
140                 return -1;
141         }
142
143         msg->elements = els;
144         msg->num_elements++;
145
146         return 0;
147 }
148
149 /*
150   add an empty element to a message
151 */
152 int ldb_msg_add(struct ldb_context *ldb,
153                 struct ldb_message *msg, 
154                 const struct ldb_message_element *el, 
155                 int flags)
156 {
157         if (ldb_msg_add_empty(ldb, msg, el->name, flags) != 0) {
158                 return -1;
159         }
160
161         msg->elements[msg->num_elements-1] = *el;
162         msg->elements[msg->num_elements-1].flags = flags;
163
164         return 0;
165 }
166
167 /*
168   add a value to a message
169 */
170 int ldb_msg_add_value(struct ldb_context *ldb,
171                       struct ldb_message *msg, 
172                       const char *attr_name,
173                       const struct ldb_val *val)
174 {
175         struct ldb_message_element *el;
176         struct ldb_val *vals;
177
178         el = ldb_msg_find_element(msg, attr_name);
179         if (!el) {
180                 ldb_msg_add_empty(ldb, msg, attr_name, 0);
181                 el = ldb_msg_find_element(msg, attr_name);
182         }
183         if (!el) {
184                 return -1;
185         }
186
187         vals = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1);
188         if (!vals) {
189                 errno = ENOMEM;
190                 return -1;
191         }
192         el->values = vals;
193         el->values[el->num_values] = *val;
194         el->num_values++;
195
196         return 0;
197 }
198
199
200 /*
201   add a string element to a message
202 */
203 int ldb_msg_add_string(struct ldb_context *ldb, struct ldb_message *msg, 
204                        const char *attr_name, const char *str)
205 {
206         struct ldb_val val;
207
208         val.data = discard_const_p(char, str);
209         val.length = strlen(str);
210
211         return ldb_msg_add_value(ldb, msg, attr_name, &val);
212 }
213
214 /*
215   add a printf formatted element to a message
216 */
217 int ldb_msg_add_fmt(struct ldb_context *ldb, struct ldb_message *msg, 
218                     const char *attr_name, const char *fmt, ...)
219 {
220         struct ldb_val val;
221         va_list ap;
222         char *str;
223
224         va_start(ap, fmt);
225         str = talloc_vasprintf(msg, fmt, ap);
226         va_end(ap);
227
228         if (str == NULL) return -1;
229
230         val.data   = str;
231         val.length = strlen(str);
232
233         return ldb_msg_add_value(ldb, msg, attr_name, &val);
234 }
235
236 /*
237   compare two ldb_message_element structures
238   assumes case senistive comparison
239 */
240 int ldb_msg_element_compare(struct ldb_message_element *el1, 
241                             struct ldb_message_element *el2)
242 {
243         unsigned int i;
244
245         if (el1->num_values != el2->num_values) {
246                 return el1->num_values - el2->num_values;
247         }
248
249         for (i=0;i<el1->num_values;i++) {
250                 if (!ldb_msg_find_val(el2, &el1->values[i])) {
251                         return -1;
252                 }
253         }
254
255         return 0;
256 }
257
258 /*
259   compare two ldb_message_element structures
260   comparing by element name
261 */
262 int ldb_msg_element_compare_name(struct ldb_message_element *el1, 
263                                  struct ldb_message_element *el2)
264 {
265         return ldb_attr_cmp(el1->name, el2->name);
266 }
267
268 /*
269   convenience functions to return common types from a message
270   these return the first value if the attribute is multi-valued
271 */
272 const struct ldb_val *ldb_msg_find_ldb_val(const struct ldb_message *msg, const char *attr_name)
273 {
274         struct ldb_message_element *el = ldb_msg_find_element(msg, attr_name);
275         if (!el || el->num_values == 0) {
276                 return NULL;
277         }
278         return &el->values[0];
279 }
280
281 int ldb_msg_find_int(const struct ldb_message *msg, 
282                      const char *attr_name,
283                      int default_value)
284 {
285         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
286         if (!v || !v->data) {
287                 return default_value;
288         }
289         return strtol(v->data, NULL, 0);
290 }
291
292 unsigned int ldb_msg_find_uint(const struct ldb_message *msg, 
293                                const char *attr_name,
294                                unsigned int default_value)
295 {
296         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
297         if (!v || !v->data) {
298                 return default_value;
299         }
300         return strtoul(v->data, NULL, 0);
301 }
302
303 int64_t ldb_msg_find_int64(const struct ldb_message *msg, 
304                            const char *attr_name,
305                            int64_t default_value)
306 {
307         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
308         if (!v || !v->data) {
309                 return default_value;
310         }
311         return strtoll(v->data, NULL, 0);
312 }
313
314 uint64_t ldb_msg_find_uint64(const struct ldb_message *msg, 
315                              const char *attr_name,
316                              uint64_t default_value)
317 {
318         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
319         if (!v || !v->data) {
320                 return default_value;
321         }
322         return strtoull(v->data, NULL, 0);
323 }
324
325 double ldb_msg_find_double(const struct ldb_message *msg, 
326                            const char *attr_name,
327                            double default_value)
328 {
329         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
330         if (!v || !v->data) {
331                 return default_value;
332         }
333         return strtod(v->data, NULL);
334 }
335
336 const char *ldb_msg_find_string(const struct ldb_message *msg, 
337                                 const char *attr_name,
338                                 const char *default_value)
339 {
340         const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
341         if (!v || !v->data) {
342                 return default_value;
343         }
344         return v->data;
345 }
346
347
348 /*
349   sort the elements of a message by name
350 */
351 void ldb_msg_sort_elements(struct ldb_message *msg)
352 {
353         qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element), 
354               (comparison_fn_t)ldb_msg_element_compare_name);
355 }
356
357
358 /*
359   free a message created using ldb_msg_copy
360 */
361 void ldb_msg_free(struct ldb_context *ldb, struct ldb_message *msg)
362 {
363         talloc_free(msg);
364 }
365
366 /*
367   copy a message, allocating new memory for all parts
368 */
369 struct ldb_message *ldb_msg_copy(struct ldb_context *ldb, 
370                                  const struct ldb_message *msg)
371 {
372         struct ldb_message *msg2;
373         int i, j;
374
375         msg2 = talloc(ldb, struct ldb_message);
376         if (msg2 == NULL) return NULL;
377
378         msg2->elements = NULL;
379         msg2->num_elements = 0;
380         msg2->private_data = NULL;
381
382         msg2->dn = talloc_strdup(msg2, msg->dn);
383         if (msg2->dn == NULL) goto failed;
384
385         msg2->elements = talloc_array(msg2, struct ldb_message_element, msg->num_elements);
386         if (msg2->elements == NULL) goto failed;
387
388         for (i=0;i<msg->num_elements;i++) {
389                 struct ldb_message_element *el1 = &msg->elements[i];
390                 struct ldb_message_element *el2 = &msg2->elements[i];
391
392                 el2->flags = el1->flags;
393                 el2->num_values = 0;
394                 el2->values = NULL;
395                 el2->name = talloc_strdup(msg2->elements, el1->name);
396                 if (el2->name == NULL) goto failed;
397                 el2->values = talloc_array(msg2->elements, struct ldb_val, el1->num_values);
398                 for (j=0;j<el1->num_values;j++) {
399                         el2->values[j] = ldb_val_dup(ldb, &el1->values[j]);
400                         if (el2->values[j].data == NULL &&
401                             el1->values[j].length != 0) {
402                                 goto failed;
403                         }
404                         el2->values[j].data = talloc_steal(el2->values, el2->values[j].data);
405                         el2->num_values++;
406                 }
407
408                 msg2->num_elements++;
409         }
410
411         return msg2;
412
413 failed:
414         talloc_free(msg2);
415         return NULL;
416 }
417
418
419 /*
420   canonicalise a message, merging elements of the same name
421 */
422 struct ldb_message *ldb_msg_canonicalize(struct ldb_context *ldb, 
423                                          const struct ldb_message *msg)
424 {
425         int i;
426         struct ldb_message *msg2;
427
428         msg2 = ldb_msg_copy(ldb, msg);
429         if (msg2 == NULL) return NULL;
430
431         ldb_msg_sort_elements(msg2);
432
433         for (i=1;i<msg2->num_elements;i++) {
434                 struct ldb_message_element *el1 = &msg2->elements[i-1];
435                 struct ldb_message_element *el2 = &msg2->elements[i];
436                 if (ldb_msg_element_compare_name(el1, el2) == 0) {
437                         el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val, 
438                                                        el1->num_values + el2->num_values);
439                         if (el1->values == NULL) {
440                                 return NULL;
441                         }
442                         memcpy(el1->values + el1->num_values,
443                                el2->values,
444                                sizeof(struct ldb_val) * el2->num_values);
445                         el1->num_values += el2->num_values;
446                         talloc_free(el2->name);
447                         if (i+1<msg2->num_elements) {
448                                 memmove(el2, el2+1, sizeof(struct ldb_message_element) * 
449                                         (msg2->num_elements - (i+1)));
450                         }
451                         msg2->num_elements--;
452                         i--;
453                 }
454         }
455
456         return msg2;
457 }
458
459
460 /*
461   return a ldb_message representing the differences between msg1 and msg2. If you
462   then use this in a ldb_modify() call it can be used to save edits to a message
463 */
464 struct ldb_message *ldb_msg_diff(struct ldb_context *ldb, 
465                                  struct ldb_message *msg1,
466                                  struct ldb_message *msg2)
467 {
468         struct ldb_message *mod;
469         struct ldb_message_element *el;
470         unsigned int i;
471
472         mod = ldb_msg_new(ldb);
473
474         mod->dn = msg1->dn;
475         mod->num_elements = 0;
476         mod->elements = NULL;
477
478         msg2 = ldb_msg_canonicalize(ldb, msg2);
479         if (msg2 == NULL) {
480                 return NULL;
481         }
482         
483         /* look in msg2 to find elements that need to be added
484            or modified */
485         for (i=0;i<msg2->num_elements;i++) {
486                 el = ldb_msg_find_element(msg1, msg2->elements[i].name);
487
488                 if (el && ldb_msg_element_compare(el, &msg2->elements[i]) == 0) {
489                         continue;
490                 }
491
492                 if (ldb_msg_add(ldb, mod, 
493                                 &msg2->elements[i],
494                                 el?LDB_FLAG_MOD_REPLACE:LDB_FLAG_MOD_ADD) != 0) {
495                         return NULL;
496                 }
497         }
498
499         /* look in msg1 to find elements that need to be deleted */
500         for (i=0;i<msg1->num_elements;i++) {
501                 el = ldb_msg_find_element(msg2, msg1->elements[i].name);
502                 if (!el) {
503                         if (ldb_msg_add_empty(ldb, mod, 
504                                               msg1->elements[i].name,
505                                               LDB_FLAG_MOD_DELETE) != 0) {
506                                 return NULL;
507                         }
508                 }
509         }
510
511         return mod;
512 }