Removed version number from file header.
[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
23 /* these are little tdb utility functions that are meant to make
24    dealing with a tdb database a little less cumbersome in Samba */
25
26 /****************************************************************************
27  Lock a chain by string.
28 ****************************************************************************/
29
30 int tdb_lock_bystring(TDB_CONTEXT *tdb, char *keyval)
31 {
32         TDB_DATA key;
33
34         key.dptr = keyval;
35         key.dsize = strlen(keyval)+1;
36         
37         return tdb_chainlock(tdb, key);
38 }
39
40 /****************************************************************************
41  Unlock a chain by string.
42 ****************************************************************************/
43
44 void tdb_unlock_bystring(TDB_CONTEXT *tdb, char *keyval)
45 {
46         TDB_DATA key;
47
48         key.dptr = keyval;
49         key.dsize = strlen(keyval)+1;
50         
51         tdb_chainunlock(tdb, key);
52 }
53
54 /****************************************************************************
55  Fetch a value by a arbitrary blob key, return -1 if not found.
56  JRA. DEPRECATED ! Use tdb_fetch_int32_byblob instead.
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         SAFE_FREE(data.dptr);
72         return ret;
73 }
74
75 /****************************************************************************
76  Fetch a value by string key, return -1 if not found.
77  JRA. DEPRECATED ! Use tdb_fetch_int32 instead.
78 ****************************************************************************/
79
80 int tdb_fetch_int(TDB_CONTEXT *tdb, char *keystr)
81 {
82         return tdb_fetch_int_byblob(tdb, keystr, strlen(keystr) + 1);
83 }
84
85 /****************************************************************************
86  Store a value by an arbitary blob key, return 0 on success, -1 on failure.
87  JRA. DEPRECATED ! Use tdb_store_int32_byblob instead.
88 ****************************************************************************/
89
90 int tdb_store_int_byblob(TDB_CONTEXT *tdb, char *keystr, size_t len, int v)
91 {
92         TDB_DATA key, data;
93
94         key.dptr = keystr;
95         key.dsize = len;
96         data.dptr = (void *)&v;
97         data.dsize = sizeof(int);
98
99         return tdb_store(tdb, key, data, TDB_REPLACE);
100 }
101
102 /****************************************************************************
103  Store a value by string key, return 0 on success, -1 on failure.
104  JRA. DEPRECATED ! Use tdb_store_int32 instead.
105 ****************************************************************************/
106
107 int tdb_store_int(TDB_CONTEXT *tdb, char *keystr, int v)
108 {
109         return tdb_store_int_byblob(tdb, keystr, strlen(keystr) + 1, v);
110 }
111
112 /****************************************************************************
113  Fetch a int32 value by a arbitrary blob key, return -1 if not found.
114  Output is int32 in native byte order.
115 ****************************************************************************/
116
117 int32 tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, char *keyval, size_t len)
118 {
119         TDB_DATA key, data;
120         int32 ret;
121
122         key.dptr = keyval;
123         key.dsize = len;
124         data = tdb_fetch(tdb, key);
125         if (!data.dptr || data.dsize != sizeof(int32))
126                 return -1;
127         
128         ret = IVAL(data.dptr,0);
129         SAFE_FREE(data.dptr);
130         return ret;
131 }
132
133 /****************************************************************************
134  Fetch a int32 value by string key, return -1 if not found.
135  Output is int32 in native byte order.
136 ****************************************************************************/
137
138 int32 tdb_fetch_int32(TDB_CONTEXT *tdb, char *keystr)
139 {
140         return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1);
141 }
142
143 /****************************************************************************
144  Store a int32 value by an arbitary blob key, return 0 on success, -1 on failure.
145  Input is int32 in native byte order. Output in tdb is in little-endian.
146 ****************************************************************************/
147
148 int tdb_store_int32_byblob(TDB_CONTEXT *tdb, char *keystr, size_t len, int32 v)
149 {
150         TDB_DATA key, data;
151         int32 v_store;
152
153         key.dptr = keystr;
154         key.dsize = len;
155         SIVAL(&v_store,0,v);
156         data.dptr = (void *)&v_store;
157         data.dsize = sizeof(int32);
158
159         return tdb_store(tdb, key, data, TDB_REPLACE);
160 }
161
162 /****************************************************************************
163  Store a int32 value by string key, return 0 on success, -1 on failure.
164  Input is int32 in native byte order. Output in tdb is in little-endian.
165 ****************************************************************************/
166
167 int tdb_store_int32(TDB_CONTEXT *tdb, char *keystr, int32 v)
168 {
169         return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v);
170 }
171
172 /****************************************************************************
173  Store a buffer by a null terminated string key.  Return 0 on success, -1
174  on failure.
175 ****************************************************************************/
176
177 int tdb_store_by_string(TDB_CONTEXT *tdb, char *keystr, void *buffer, int len)
178 {
179     TDB_DATA key, data;
180
181     key.dptr = keystr;
182     key.dsize = strlen(keystr) + 1;
183
184     data.dptr = buffer;
185     data.dsize = len;
186
187     return tdb_store(tdb, key, data, TDB_REPLACE);
188 }
189
190 /****************************************************************************
191  Fetch a buffer using a null terminated string key.  Don't forget to call
192  free() on the result dptr.
193 ****************************************************************************/
194
195 TDB_DATA tdb_fetch_by_string(TDB_CONTEXT *tdb, char *keystr)
196 {
197     TDB_DATA key;
198
199     key.dptr = keystr;
200     key.dsize = strlen(keystr) + 1;
201
202     return tdb_fetch(tdb, key);
203 }
204
205 /****************************************************************************
206  Atomic integer change. Returns old value. To create, set initial value in *oldval. 
207  Deprecated. Use int32 version. JRA.
208 ****************************************************************************/
209
210 int tdb_change_int_atomic(TDB_CONTEXT *tdb, char *keystr, int *oldval, int change_val)
211 {
212         int val;
213         int ret = -1;
214
215         if (tdb_lock_bystring(tdb, keystr) == -1)
216                 return -1;
217
218         if ((val = tdb_fetch_int(tdb, keystr)) == -1) {
219                 if (tdb_error(tdb) != TDB_ERR_NOEXIST)
220                         goto err_out;
221
222                 val = *oldval;
223
224         } else {
225                 *oldval = val;
226                 val += change_val;
227         }
228                 
229         if (tdb_store_int(tdb, keystr, val) == -1)
230                 goto err_out;
231
232         ret = 0;
233
234   err_out:
235
236         tdb_unlock_bystring(tdb, keystr);
237         return ret;
238 }
239
240 /****************************************************************************
241  Atomic integer change. Returns old value. To create, set initial value in *oldval. 
242 ****************************************************************************/
243
244 int32 tdb_change_int32_atomic(TDB_CONTEXT *tdb, char *keystr, int32 *oldval, int32 change_val)
245 {
246         int32 val;
247         int32 ret = -1;
248
249         if (tdb_lock_bystring(tdb, keystr) == -1)
250                 return -1;
251
252         if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
253                 if (tdb_error(tdb) != TDB_ERR_NOEXIST)
254                         goto err_out;
255
256                 val = *oldval;
257
258         } else {
259                 *oldval = val;
260                 val += change_val;
261         }
262                 
263         if (tdb_store_int32(tdb, keystr, val) == -1)
264                 goto err_out;
265
266         ret = 0;
267
268   err_out:
269
270         tdb_unlock_bystring(tdb, keystr);
271         return ret;
272 }
273
274 /****************************************************************************
275  Useful pair of routines for packing/unpacking data consisting of
276  integers and strings.
277 ****************************************************************************/
278
279 size_t tdb_pack(char *buf, int bufsize, char *fmt, ...)
280 {
281         va_list ap;
282         uint16 w;
283         uint32 d;
284         int i;
285         void *p;
286         int len;
287         char *s;
288         char c;
289         char *buf0 = buf;
290         char *fmt0 = fmt;
291         int bufsize0 = bufsize;
292
293         va_start(ap, fmt);
294
295         while (*fmt) {
296                 switch ((c = *fmt++)) {
297                 case 'w':
298                         len = 2;
299                         w = (uint16)va_arg(ap, int);
300                         if (bufsize >= len)
301                                 SSVAL(buf, 0, w);
302                         break;
303                 case 'd':
304                         len = 4;
305                         d = va_arg(ap, uint32);
306                         if (bufsize >= len)
307                                 SIVAL(buf, 0, d);
308                         break;
309                 case 'p':
310                         len = 4;
311                         p = va_arg(ap, void *);
312                         d = p?1:0;
313                         if (bufsize >= len)
314                                 SIVAL(buf, 0, d);
315                         break;
316                 case 'P':
317                         s = va_arg(ap,char *);
318                         w = strlen(s);
319                         len = w + 1;
320                         if (bufsize >= len)
321                                 memcpy(buf, s, len);
322                         break;
323                 case 'f':
324                         s = va_arg(ap,char *);
325                         w = strlen(s);
326                         len = w + 1;
327                         if (bufsize >= len)
328                                 memcpy(buf, s, len);
329                         break;
330                 case 'B':
331                         i = va_arg(ap, int);
332                         s = va_arg(ap, char *);
333                         len = 4+i;
334                         if (bufsize >= len) {
335                                 SIVAL(buf, 0, i);
336                                 memcpy(buf+4, s, i);
337                         }
338                         break;
339                 default:
340                         DEBUG(0,("Unknown tdb_pack format %c in %s\n", 
341                                  c, fmt));
342                         len = 0;
343                         break;
344                 }
345
346                 buf += len;
347                 bufsize -= len;
348         }
349
350         va_end(ap);
351
352         DEBUG(18,("tdb_pack(%s, %d) -> %d\n", 
353                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
354         
355         return PTR_DIFF(buf, buf0);
356 }
357
358 /****************************************************************************
359  Useful pair of routines for packing/unpacking data consisting of
360  integers and strings.
361 ****************************************************************************/
362
363 int tdb_unpack(char *buf, int bufsize, char *fmt, ...)
364 {
365         va_list ap;
366         uint16 *w;
367         uint32 *d;
368         int len;
369         int *i;
370         void **p;
371         char *s, **b;
372         char c;
373         char *buf0 = buf;
374         char *fmt0 = fmt;
375         int bufsize0 = bufsize;
376
377         va_start(ap, fmt);
378         
379         while (*fmt) {
380                 switch ((c=*fmt++)) {
381                 case 'w':
382                         len = 2;
383                         w = va_arg(ap, uint16 *);
384                         if (bufsize < len)
385                                 goto no_space;
386                         *w = SVAL(buf, 0);
387                         break;
388                 case 'd':
389                         len = 4;
390                         d = va_arg(ap, uint32 *);
391                         if (bufsize < len)
392                                 goto no_space;
393                         *d = IVAL(buf, 0);
394                         break;
395                 case 'p':
396                         len = 4;
397                         p = va_arg(ap, void **);
398                         if (bufsize < len)
399                                 goto no_space;
400                         *p = (void *)IVAL(buf, 0);
401                         break;
402                 case 'P':
403                         s = va_arg(ap,char *);
404                         len = strlen(buf) + 1;
405                         if (bufsize < len || len > sizeof(pstring))
406                                 goto no_space;
407                         memcpy(s, buf, len);
408                         break;
409                 case 'f':
410                         s = va_arg(ap,char *);
411                         len = strlen(buf) + 1;
412                         if (bufsize < len || len > sizeof(fstring))
413                                 goto no_space;
414                         memcpy(s, buf, len);
415                         break;
416                 case 'B':
417                         i = va_arg(ap, int *);
418                         b = va_arg(ap, char **);
419                         len = 4;
420                         if (bufsize < len)
421                                 goto no_space;
422                         *i = IVAL(buf, 0);
423                         if (! *i) {
424                                 *b = NULL;
425                                 break;
426                         }
427                         len += *i;
428                         if (bufsize < len)
429                                 goto no_space;
430                         *b = (char *)malloc(*i);
431                         if (! *b)
432                                 goto no_space;
433                         memcpy(*b, buf+4, *i);
434                         break;
435                 default:
436                         DEBUG(0,("Unknown tdb_unpack format %c in %s\n", 
437                                  c, fmt));
438
439                         len = 0;
440                         break;
441                 }
442
443                 buf += len;
444                 bufsize -= len;
445         }
446
447         va_end(ap);
448
449         DEBUG(18,("tdb_unpack(%s, %d) -> %d\n", 
450                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
451
452         return PTR_DIFF(buf, buf0);
453
454  no_space:
455         return -1;
456 }
457
458 /****************************************************************************
459  Log tdb messages via DEBUG().
460 ****************************************************************************/
461
462 static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
463 {
464         va_list ap;
465         char *ptr = NULL;
466
467         va_start(ap, format);
468         vasprintf(&ptr, format, ap);
469         va_end(ap);
470         
471         if (!ptr || !*ptr)
472                 return;
473
474         DEBUG(level, ("tdb(%s): %s", tdb->name ? tdb->name : "unknown", ptr));
475         SAFE_FREE(ptr);
476 }
477
478 /****************************************************************************
479  Like tdb_open() but also setup a logging function that redirects to
480  the samba DEBUG() system.
481 ****************************************************************************/
482
483 TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
484                           int open_flags, mode_t mode)
485 {
486         TDB_CONTEXT *tdb;
487
488         if (!lp_use_mmap())
489                 tdb_flags |= TDB_NOMMAP;
490
491         tdb = tdb_open_ex(name, hash_size, tdb_flags, 
492                                     open_flags, mode, tdb_log);
493         if (!tdb)
494                 return NULL;
495
496         return tdb;
497 }
498
499
500 /****************************************************************************
501  Allow tdb_delete to be used as a tdb_traversal_fn.
502 ****************************************************************************/
503
504 int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
505                      void *state)
506 {
507     return tdb_delete(the_tdb, key);
508 }