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