22ead16e1fccb9290caaaa5a35306ce227e6e24f
[ira/wip.git] / source3 / tdb / tdbutil.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    tdb utility functions
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.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 value by a arbitrary blob key, return -1 if not found.
57 ****************************************************************************/
58
59 int tdb_fetch_int_byblob(TDB_CONTEXT *tdb, char *keyval, size_t len)
60 {
61         TDB_DATA key, data;
62         int ret;
63
64         key.dptr = keyval;
65         key.dsize = len;
66         data = tdb_fetch(tdb, key);
67         if (!data.dptr || data.dsize != sizeof(int))
68                 return -1;
69         
70         memcpy(&ret, data.dptr, sizeof(int));
71         free(data.dptr);
72         return ret;
73 }
74
75 /****************************************************************************
76  Fetch a value by string key, return -1 if not found.
77 ****************************************************************************/
78
79 int tdb_fetch_int(TDB_CONTEXT *tdb, char *keystr)
80 {
81         return tdb_fetch_int_byblob(tdb, keystr, strlen(keystr) + 1);
82 }
83
84 /****************************************************************************
85  Store a value by an arbitary blob key, return 0 on success, -1 on failure.
86 ****************************************************************************/
87
88 int tdb_store_int_byblob(TDB_CONTEXT *tdb, char *keystr, size_t len, int v)
89 {
90         TDB_DATA key, data;
91
92         key.dptr = keystr;
93         key.dsize = len;
94         data.dptr = (void *)&v;
95         data.dsize = sizeof(int);
96
97         return tdb_store(tdb, key, data, TDB_REPLACE);
98 }
99
100 /****************************************************************************
101  Store a value by string key, return 0 on success, -1 on failure.
102 ****************************************************************************/
103
104 int tdb_store_int(TDB_CONTEXT *tdb, char *keystr, int v)
105 {
106         return tdb_store_int_byblob(tdb, keystr, strlen(keystr) + 1, v);
107 }
108
109 /****************************************************************************
110  Store a buffer by a null terminated string key.  Return 0 on success, -1
111  on failure.
112 ****************************************************************************/
113
114 int tdb_store_by_string(TDB_CONTEXT *tdb, char *keystr, void *buffer, int len)
115 {
116     TDB_DATA key, data;
117
118     key.dptr = keystr;
119     key.dsize = strlen(keystr) + 1;
120
121     data.dptr = buffer;
122     data.dsize = len;
123
124     return tdb_store(tdb, key, data, TDB_REPLACE);
125 }
126
127 /****************************************************************************
128  Fetch a buffer using a null terminated string key.  Don't forget to call
129  free() on the result dptr.
130 ****************************************************************************/
131
132 TDB_DATA tdb_fetch_by_string(TDB_CONTEXT *tdb, char *keystr)
133 {
134     TDB_DATA key;
135
136     key.dptr = keystr;
137     key.dsize = strlen(keystr) + 1;
138
139     return tdb_fetch(tdb, key);
140 }
141
142 /****************************************************************************
143  Atomic integer change. Returns old value. To create, set initial value in *oldval. 
144 ****************************************************************************/
145
146 int tdb_change_int_atomic(TDB_CONTEXT *tdb, char *keystr, int *oldval, int change_val)
147 {
148         int val;
149         int ret = -1;
150
151         if (tdb_lock_bystring(tdb, keystr) == -1)
152                 return -1;
153
154         if ((val = tdb_fetch_int(tdb, keystr)) == -1) {
155                 if (tdb_error(tdb) != TDB_ERR_NOEXIST)
156                         goto err_out;
157
158                 val = *oldval;
159
160         } else {
161                 *oldval = val;
162                 val += change_val;
163         }
164                 
165         if (tdb_store_int(tdb, keystr, val) == -1)
166                 goto err_out;
167
168         ret = 0;
169
170   err_out:
171
172         tdb_unlock_bystring(tdb, keystr);
173         return ret;
174 }
175
176 /****************************************************************************
177  Useful pair of routines for packing/unpacking data consisting of
178  integers and strings.
179 ****************************************************************************/
180
181 size_t tdb_pack(char *buf, int bufsize, char *fmt, ...)
182 {
183         va_list ap;
184         uint16 w;
185         uint32 d;
186         int i;
187         void *p;
188         int len;
189         char *s;
190         char c;
191         char *buf0 = buf;
192         char *fmt0 = fmt;
193         int bufsize0 = bufsize;
194
195         va_start(ap, fmt);
196
197         while (*fmt) {
198                 switch ((c = *fmt++)) {
199                 case 'w':
200                         len = 2;
201                         w = (uint16)va_arg(ap, int);
202                         if (bufsize >= len)
203                                 SSVAL(buf, 0, w);
204                         break;
205                 case 'd':
206                         len = 4;
207                         d = va_arg(ap, uint32);
208                         if (bufsize >= len)
209                                 SIVAL(buf, 0, d);
210                         break;
211                 case 'p':
212                         len = 4;
213                         p = va_arg(ap, void *);
214                         d = p?1:0;
215                         if (bufsize >= len)
216                                 SIVAL(buf, 0, d);
217                         break;
218                 case 'P':
219                         s = va_arg(ap,char *);
220                         w = strlen(s);
221                         len = w + 1;
222                         if (bufsize >= len)
223                                 memcpy(buf, s, len);
224                         break;
225                 case 'f':
226                         s = va_arg(ap,char *);
227                         w = strlen(s);
228                         len = w + 1;
229                         if (bufsize >= len)
230                                 memcpy(buf, s, len);
231                         break;
232                 case 'B':
233                         i = va_arg(ap, int);
234                         s = va_arg(ap, char *);
235                         len = 4+i;
236                         if (bufsize >= len) {
237                                 SIVAL(buf, 0, i);
238                                 memcpy(buf+4, s, i);
239                         }
240                         break;
241                 default:
242                         DEBUG(0,("Unknown tdb_pack format %c in %s\n", 
243                                  c, fmt));
244                         len = 0;
245                         break;
246                 }
247
248                 buf += len;
249                 bufsize -= len;
250         }
251
252         va_end(ap);
253
254         DEBUG(18,("tdb_pack(%s, %d) -> %d\n", 
255                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
256         
257         return PTR_DIFF(buf, buf0);
258 }
259
260 /****************************************************************************
261  Useful pair of routines for packing/unpacking data consisting of
262  integers and strings.
263 ****************************************************************************/
264
265 int tdb_unpack(char *buf, int bufsize, char *fmt, ...)
266 {
267         va_list ap;
268         uint16 *w;
269         uint32 *d;
270         int len;
271         int *i;
272         void **p;
273         char *s, **b;
274         char c;
275         char *buf0 = buf;
276         char *fmt0 = fmt;
277         int bufsize0 = bufsize;
278
279         va_start(ap, fmt);
280         
281         while (*fmt) {
282                 switch ((c=*fmt++)) {
283                 case 'w':
284                         len = 2;
285                         w = va_arg(ap, uint16 *);
286                         if (bufsize < len)
287                                 goto no_space;
288                         *w = SVAL(buf, 0);
289                         break;
290                 case 'd':
291                         len = 4;
292                         d = va_arg(ap, uint32 *);
293                         if (bufsize < len)
294                                 goto no_space;
295                         *d = IVAL(buf, 0);
296                         break;
297                 case 'p':
298                         len = 4;
299                         p = va_arg(ap, void **);
300                         if (bufsize < len)
301                                 goto no_space;
302                         *p = (void *)IVAL(buf, 0);
303                         break;
304                 case 'P':
305                         s = va_arg(ap,char *);
306                         len = strlen(buf) + 1;
307                         if (bufsize < len || len > sizeof(pstring))
308                                 goto no_space;
309                         memcpy(s, buf, len);
310                         break;
311                 case 'f':
312                         s = va_arg(ap,char *);
313                         len = strlen(buf) + 1;
314                         if (bufsize < len || len > sizeof(fstring))
315                                 goto no_space;
316                         memcpy(s, buf, len);
317                         break;
318                 case 'B':
319                         i = va_arg(ap, int *);
320                         b = va_arg(ap, char **);
321                         len = 4;
322                         if (bufsize < len)
323                                 goto no_space;
324                         *i = IVAL(buf, 0);
325                         if (! *i) {
326                                 *b = NULL;
327                                 break;
328                         }
329                         len += *i;
330                         if (bufsize < len)
331                                 goto no_space;
332                         *b = (char *)malloc(*i);
333                         if (! *b)
334                                 goto no_space;
335                         memcpy(*b, buf+4, *i);
336                         break;
337                 default:
338                         DEBUG(0,("Unknown tdb_unpack format %c in %s\n", 
339                                  c, fmt));
340
341                         len = 0;
342                         break;
343                 }
344
345                 buf += len;
346                 bufsize -= len;
347         }
348
349         va_end(ap);
350
351         DEBUG(18,("tdb_unpack(%s, %d) -> %d\n", 
352                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
353
354         return PTR_DIFF(buf, buf0);
355
356  no_space:
357         return -1;
358 }
359
360 /****************************************************************************
361  Log tdb messages via DEBUG().
362 ****************************************************************************/
363
364 static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
365 {
366         va_list ap;
367         char *ptr = NULL;
368
369         va_start(ap, format);
370         vasprintf(&ptr, format, ap);
371         va_end(ap);
372         
373         if (!ptr || !*ptr)
374                 return;
375
376         DEBUG(level, ("tdb(%s): %s", tdb->name, ptr));
377         free(ptr);
378 }
379
380 /****************************************************************************
381  Like tdb_open() but also setup a logging function that redirects to
382  the samba DEBUG() system.
383 ****************************************************************************/
384
385 TDB_CONTEXT *tdb_open_log(char *name, int hash_size, int tdb_flags,
386                           int open_flags, mode_t mode)
387 {
388         TDB_CONTEXT *tdb;
389
390         if (!lp_use_mmap())
391                 tdb_flags |= TDB_NOMMAP;
392
393         tdb = tdb_open(name, hash_size, tdb_flags, 
394                                     open_flags, mode);
395         if (!tdb)
396                 return NULL;
397
398         tdb_logging_function(tdb, tdb_log);
399
400         return tdb;
401 }
402
403
404 /****************************************************************************
405  Allow tdb_delete to be used as a tdb_traversal_fn.
406 ****************************************************************************/
407
408 int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
409                      void *state)
410 {
411     return tdb_delete(the_tdb, key);
412 }