updated the 3.0 branch from the head branch - ready for alpha18
[ira/wip.git] / source3 / tdb / tdbutil.c
1 /* 
2    Unix SMB/CIFS implementation.
3    tdb utility functions
4    Copyright (C) Andrew Tridgell 1992-1998
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include <fnmatch.h>
23
24 /* these are little tdb utility functions that are meant to make
25    dealing with a tdb database a little less cumbersome in Samba */
26
27 /****************************************************************************
28  Lock a chain by string.
29 ****************************************************************************/
30
31 int tdb_lock_bystring(TDB_CONTEXT *tdb, char *keyval)
32 {
33         TDB_DATA key;
34
35         key.dptr = keyval;
36         key.dsize = strlen(keyval)+1;
37         
38         return tdb_chainlock(tdb, key);
39 }
40
41 /****************************************************************************
42  Unlock a chain by string.
43 ****************************************************************************/
44
45 void tdb_unlock_bystring(TDB_CONTEXT *tdb, char *keyval)
46 {
47         TDB_DATA key;
48
49         key.dptr = keyval;
50         key.dsize = strlen(keyval)+1;
51         
52         tdb_chainunlock(tdb, key);
53 }
54
55 /****************************************************************************
56  Fetch a int32 value by a arbitrary blob key, return -1 if not found.
57  Output is int32 in native byte order.
58 ****************************************************************************/
59
60 int32 tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, char *keyval, size_t len)
61 {
62         TDB_DATA key, data;
63         int32 ret;
64
65         key.dptr = keyval;
66         key.dsize = len;
67         data = tdb_fetch(tdb, key);
68         if (!data.dptr || data.dsize != sizeof(int32))
69                 return -1;
70         
71         ret = IVAL(data.dptr,0);
72         SAFE_FREE(data.dptr);
73         return ret;
74 }
75
76 /****************************************************************************
77  Fetch a int32 value by string key, return -1 if not found.
78  Output is int32 in native byte order.
79 ****************************************************************************/
80
81 int32 tdb_fetch_int32(TDB_CONTEXT *tdb, char *keystr)
82 {
83         return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1);
84 }
85
86 /****************************************************************************
87  Store a int32 value by an arbitary blob key, return 0 on success, -1 on failure.
88  Input is int32 in native byte order. Output in tdb is in little-endian.
89 ****************************************************************************/
90
91 int tdb_store_int32_byblob(TDB_CONTEXT *tdb, char *keystr, size_t len, int32 v)
92 {
93         TDB_DATA key, data;
94         int32 v_store;
95
96         key.dptr = keystr;
97         key.dsize = len;
98         SIVAL(&v_store,0,v);
99         data.dptr = (void *)&v_store;
100         data.dsize = sizeof(int32);
101
102         return tdb_store(tdb, key, data, TDB_REPLACE);
103 }
104
105 /****************************************************************************
106  Store a int32 value by string key, return 0 on success, -1 on failure.
107  Input is int32 in native byte order. Output in tdb is in little-endian.
108 ****************************************************************************/
109
110 int tdb_store_int32(TDB_CONTEXT *tdb, char *keystr, int32 v)
111 {
112         return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v);
113 }
114
115 /****************************************************************************
116  Fetch a uint32 value by a arbitrary blob key, return -1 if not found.
117  Output is uint32 in native byte order.
118 ****************************************************************************/
119
120 BOOL tdb_fetch_uint32_byblob(TDB_CONTEXT *tdb, char *keyval, size_t len, uint32 *value)
121 {
122         TDB_DATA key, data;
123
124         key.dptr = keyval;
125         key.dsize = len;
126         data = tdb_fetch(tdb, key);
127         if (!data.dptr || data.dsize != sizeof(uint32))
128                 return False;
129         
130         *value = IVAL(data.dptr,0);
131         SAFE_FREE(data.dptr);
132         return True;
133 }
134
135 /****************************************************************************
136  Fetch a uint32 value by string key, return -1 if not found.
137  Output is uint32 in native byte order.
138 ****************************************************************************/
139
140 BOOL tdb_fetch_uint32(TDB_CONTEXT *tdb, char *keystr, uint32 *value)
141 {
142         return tdb_fetch_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
143 }
144
145 /****************************************************************************
146  Store a uint32 value by an arbitary blob key, return 0 on success, -1 on failure.
147  Input is uint32 in native byte order. Output in tdb is in little-endian.
148 ****************************************************************************/
149
150 BOOL tdb_store_uint32_byblob(TDB_CONTEXT *tdb, char *keystr, size_t len, uint32 value)
151 {
152         TDB_DATA key, data;
153         uint32 v_store;
154         BOOL ret = True;
155
156         key.dptr = keystr;
157         key.dsize = len;
158         SIVAL(&v_store, 0, value);
159         data.dptr = (void *)&v_store;
160         data.dsize = sizeof(uint32);
161
162         if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
163                 ret = False;
164
165         return ret;
166 }
167
168 /****************************************************************************
169  Store a uint32 value by string key, return 0 on success, -1 on failure.
170  Input is uint32 in native byte order. Output in tdb is in little-endian.
171 ****************************************************************************/
172
173 BOOL tdb_store_uint32(TDB_CONTEXT *tdb, char *keystr, uint32 value)
174 {
175         return tdb_store_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
176 }
177 /****************************************************************************
178  Store a buffer by a null terminated string key.  Return 0 on success, -1
179  on failure.
180 ****************************************************************************/
181
182 int tdb_store_by_string(TDB_CONTEXT *tdb, char *keystr, void *buffer, int len)
183 {
184     TDB_DATA key, data;
185
186     key.dptr = keystr;
187     key.dsize = strlen(keystr) + 1;
188
189     data.dptr = buffer;
190     data.dsize = len;
191
192     return tdb_store(tdb, key, data, TDB_REPLACE);
193 }
194
195 /****************************************************************************
196  Fetch a buffer using a null terminated string key.  Don't forget to call
197  free() on the result dptr.
198 ****************************************************************************/
199
200 TDB_DATA tdb_fetch_by_string(TDB_CONTEXT *tdb, char *keystr)
201 {
202     TDB_DATA key;
203
204     key.dptr = keystr;
205     key.dsize = strlen(keystr) + 1;
206
207     return tdb_fetch(tdb, key);
208 }
209
210 /****************************************************************************
211  Delete a buffer using a null terminated string key.
212 ****************************************************************************/
213
214 int tdb_delete_by_string(TDB_CONTEXT *tdb, char *keystr)
215 {
216         TDB_DATA key;
217
218         key.dptr = keystr;
219         key.dsize = strlen(keystr) + 1;
220
221         return tdb_delete(tdb, key);
222 }
223
224 /****************************************************************************
225  Atomic integer change. Returns old value. To create, set initial value in *oldval. 
226 ****************************************************************************/
227
228 int32 tdb_change_int32_atomic(TDB_CONTEXT *tdb, char *keystr, int32 *oldval, int32 change_val)
229 {
230         int32 val;
231         int32 ret = -1;
232
233         if (tdb_lock_bystring(tdb, keystr) == -1)
234                 return -1;
235
236         if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
237                 /* The lookup failed */
238                 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
239                         /* but not becouse it didn't exist */
240                         goto err_out;
241                 }
242                 
243                 /* Start with 'old' value */
244                 val = *oldval;
245
246         } else {
247                 /* It worked, set return value (oldval) to tdb data */
248                 *oldval = val;
249         }
250
251         /* Increment value for storage and return next time */
252         val += change_val;
253                 
254         if (tdb_store_int32(tdb, keystr, val) == -1)
255                 goto err_out;
256
257         ret = 0;
258
259   err_out:
260
261         tdb_unlock_bystring(tdb, keystr);
262         return ret;
263 }
264
265 /****************************************************************************
266  Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval. 
267 ****************************************************************************/
268
269 BOOL tdb_change_uint32_atomic(TDB_CONTEXT *tdb, char *keystr, uint32 *oldval, uint32 change_val)
270 {
271         uint32 val;
272         BOOL ret = False;
273
274         if (tdb_lock_bystring(tdb, keystr) == -1)
275                 return False;
276
277         if (!tdb_fetch_uint32(tdb, keystr, &val)) {
278                 /* It failed */
279                 if (tdb_error(tdb) != TDB_ERR_NOEXIST) { 
280                         /* and not becouse it didn't exist */
281                         goto err_out;
282                 }
283
284                 /* Start with 'old' value */
285                 val = *oldval;
286
287         } else {
288                 /* it worked, set return value (oldval) to tdb data */
289                 *oldval = val;
290
291         }
292
293         /* get a new value to store */
294         val += change_val;
295                 
296         if (!tdb_store_uint32(tdb, keystr, val))
297                 goto err_out;
298
299         ret = True;
300
301   err_out:
302
303         tdb_unlock_bystring(tdb, keystr);
304         return ret;
305 }
306
307 /****************************************************************************
308  Useful pair of routines for packing/unpacking data consisting of
309  integers and strings.
310 ****************************************************************************/
311
312 size_t tdb_pack(char *buf, int bufsize, char *fmt, ...)
313 {
314         va_list ap;
315         uint16 w;
316         uint32 d;
317         int i;
318         void *p;
319         int len;
320         char *s;
321         char c;
322         char *buf0 = buf;
323         char *fmt0 = fmt;
324         int bufsize0 = bufsize;
325
326         va_start(ap, fmt);
327
328         while (*fmt) {
329                 switch ((c = *fmt++)) {
330                 case 'w':
331                         len = 2;
332                         w = (uint16)va_arg(ap, int);
333                         if (bufsize >= len)
334                                 SSVAL(buf, 0, w);
335                         break;
336                 case 'd':
337                         len = 4;
338                         d = va_arg(ap, uint32);
339                         if (bufsize >= len)
340                                 SIVAL(buf, 0, d);
341                         break;
342                 case 'p':
343                         len = 4;
344                         p = va_arg(ap, void *);
345                         d = p?1:0;
346                         if (bufsize >= len)
347                                 SIVAL(buf, 0, d);
348                         break;
349                 case 'P':
350                         s = va_arg(ap,char *);
351                         w = strlen(s);
352                         len = w + 1;
353                         if (bufsize >= len)
354                                 memcpy(buf, s, len);
355                         break;
356                 case 'f':
357                         s = va_arg(ap,char *);
358                         w = strlen(s);
359                         len = w + 1;
360                         if (bufsize >= len)
361                                 memcpy(buf, s, len);
362                         break;
363                 case 'B':
364                         i = va_arg(ap, int);
365                         s = va_arg(ap, char *);
366                         len = 4+i;
367                         if (bufsize >= len) {
368                                 SIVAL(buf, 0, i);
369                                 memcpy(buf+4, s, i);
370                         }
371                         break;
372                 default:
373                         DEBUG(0,("Unknown tdb_pack format %c in %s\n", 
374                                  c, fmt));
375                         len = 0;
376                         break;
377                 }
378
379                 buf += len;
380                 bufsize -= len;
381         }
382
383         va_end(ap);
384
385         DEBUG(18,("tdb_pack(%s, %d) -> %d\n", 
386                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
387         
388         return PTR_DIFF(buf, buf0);
389 }
390
391 /****************************************************************************
392  Useful pair of routines for packing/unpacking data consisting of
393  integers and strings.
394 ****************************************************************************/
395
396 int tdb_unpack(char *buf, int bufsize, char *fmt, ...)
397 {
398         va_list ap;
399         uint16 *w;
400         uint32 *d;
401         int len;
402         int *i;
403         void **p;
404         char *s, **b;
405         char c;
406         char *buf0 = buf;
407         char *fmt0 = fmt;
408         int bufsize0 = bufsize;
409
410         va_start(ap, fmt);
411         
412         while (*fmt) {
413                 switch ((c=*fmt++)) {
414                 case 'w':
415                         len = 2;
416                         w = va_arg(ap, uint16 *);
417                         if (bufsize < len)
418                                 goto no_space;
419                         *w = SVAL(buf, 0);
420                         break;
421                 case 'd':
422                         len = 4;
423                         d = va_arg(ap, uint32 *);
424                         if (bufsize < len)
425                                 goto no_space;
426                         *d = IVAL(buf, 0);
427                         break;
428                 case 'p':
429                         len = 4;
430                         p = va_arg(ap, void **);
431                         if (bufsize < len)
432                                 goto no_space;
433                         *p = (void *)IVAL(buf, 0);
434                         break;
435                 case 'P':
436                         s = va_arg(ap,char *);
437                         len = strlen(buf) + 1;
438                         if (bufsize < len || len > sizeof(pstring))
439                                 goto no_space;
440                         memcpy(s, buf, len);
441                         break;
442                 case 'f':
443                         s = va_arg(ap,char *);
444                         len = strlen(buf) + 1;
445                         if (bufsize < len || len > sizeof(fstring))
446                                 goto no_space;
447                         memcpy(s, buf, len);
448                         break;
449                 case 'B':
450                         i = va_arg(ap, int *);
451                         b = va_arg(ap, char **);
452                         len = 4;
453                         if (bufsize < len)
454                                 goto no_space;
455                         *i = IVAL(buf, 0);
456                         if (! *i) {
457                                 *b = NULL;
458                                 break;
459                         }
460                         len += *i;
461                         if (bufsize < len)
462                                 goto no_space;
463                         *b = (char *)malloc(*i);
464                         if (! *b)
465                                 goto no_space;
466                         memcpy(*b, buf+4, *i);
467                         break;
468                 default:
469                         DEBUG(0,("Unknown tdb_unpack format %c in %s\n", 
470                                  c, fmt));
471
472                         len = 0;
473                         break;
474                 }
475
476                 buf += len;
477                 bufsize -= len;
478         }
479
480         va_end(ap);
481
482         DEBUG(18,("tdb_unpack(%s, %d) -> %d\n", 
483                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
484
485         return PTR_DIFF(buf, buf0);
486
487  no_space:
488         return -1;
489 }
490
491 /****************************************************************************
492  Log tdb messages via DEBUG().
493 ****************************************************************************/
494
495 static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
496 {
497         va_list ap;
498         char *ptr = NULL;
499
500         va_start(ap, format);
501         vasprintf(&ptr, format, ap);
502         va_end(ap);
503         
504         if (!ptr || !*ptr)
505                 return;
506
507         DEBUG(level, ("tdb(%s): %s", tdb->name ? tdb->name : "unnamed", ptr));
508         SAFE_FREE(ptr);
509 }
510
511 /****************************************************************************
512  Like tdb_open() but also setup a logging function that redirects to
513  the samba DEBUG() system.
514 ****************************************************************************/
515
516 TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
517                           int open_flags, mode_t mode)
518 {
519         TDB_CONTEXT *tdb;
520
521         if (!lp_use_mmap())
522                 tdb_flags |= TDB_NOMMAP;
523
524         tdb = tdb_open_ex(name, hash_size, tdb_flags, 
525                                     open_flags, mode, tdb_log);
526         if (!tdb)
527                 return NULL;
528
529         return tdb;
530 }
531
532
533 /****************************************************************************
534  Allow tdb_delete to be used as a tdb_traversal_fn.
535 ****************************************************************************/
536
537 int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
538                      void *state)
539 {
540     return tdb_delete(the_tdb, key);
541 }
542
543
544
545 /**
546  * Search across the whole tdb for keys that match the given pattern
547  * return the result as a list of keys
548  *
549  * @param tdb pointer to opened tdb file context
550  * @param pattern searching pattern used by fnmatch(3) functions
551  *
552  * @return list of keys found by looking up with given pattern
553  **/
554 TDB_LIST_NODE *tdb_search_keys(TDB_CONTEXT *tdb, const char* pattern)
555 {
556         TDB_DATA key, next;
557         TDB_LIST_NODE *list = NULL;
558         TDB_LIST_NODE *rec = NULL;
559         TDB_LIST_NODE *tmp = NULL;
560         
561         for (key = tdb_firstkey(tdb); key.dptr; key = next) {
562                 /* duplicate key string to ensure null-termination */
563                 char *key_str = (char*) strndup(key.dptr, key.dsize);
564                 if (!key_str) {
565                         DEBUG(0, ("tdb_search_keys: strndup() failed!\n"));
566                         smb_panic("strndup failed!\n");
567                 }
568                 
569                 DEBUG(18, ("checking %s for match to pattern %s\n", key_str, pattern));
570                 
571                 next = tdb_nextkey(tdb, key);
572
573                 /* do the pattern checking */
574                 if (fnmatch(pattern, key_str, 0) == 0) {
575                         rec = (TDB_LIST_NODE*) malloc(sizeof(*rec));
576                         ZERO_STRUCTP(rec);
577
578                         rec->node_key = key;
579         
580                         DLIST_ADD_END(list, rec, tmp);
581                 
582                         DEBUG(18, ("checking %s matched pattern %s\n", key_str, pattern));
583                 } else {
584                         free(key.dptr);
585                 }
586                 
587                 /* free duplicated key string */
588                 free(key_str);
589         }
590         
591         return list;
592
593 };
594
595
596 /**
597  * Free the list returned by tdb_search_keys
598  *
599  * @param node list of results found by tdb_search_keys
600  **/
601 void tdb_search_list_free(TDB_LIST_NODE* node)
602 {
603         TDB_LIST_NODE *next_node;
604         
605         while (node) {
606                 next_node = node->next;
607                 SAFE_FREE(node);
608                 node = next_node;
609         };
610 };
611
612