Added int32 versions of the endian-dependent code.
[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  JRA. DEPRECATED ! Use tdb_fetch_int32_byblob instead.
58 ****************************************************************************/
59
60 int tdb_fetch_int_byblob(TDB_CONTEXT *tdb, char *keyval, size_t len)
61 {
62         TDB_DATA key, data;
63         int ret;
64
65         key.dptr = keyval;
66         key.dsize = len;
67         data = tdb_fetch(tdb, key);
68         if (!data.dptr || data.dsize != sizeof(int))
69                 return -1;
70         
71         memcpy(&ret, data.dptr, sizeof(int));
72         SAFE_FREE(data.dptr);
73         return ret;
74 }
75
76 /****************************************************************************
77  Fetch a value by string key, return -1 if not found.
78  JRA. DEPRECATED ! Use tdb_fetch_int32 instead.
79 ****************************************************************************/
80
81 int tdb_fetch_int(TDB_CONTEXT *tdb, char *keystr)
82 {
83         return tdb_fetch_int_byblob(tdb, keystr, strlen(keystr) + 1);
84 }
85
86 /****************************************************************************
87  Store a value by an arbitary blob key, return 0 on success, -1 on failure.
88  JRA. DEPRECATED ! Use tdb_store_int32_byblob instead.
89 ****************************************************************************/
90
91 int tdb_store_int_byblob(TDB_CONTEXT *tdb, char *keystr, size_t len, int v)
92 {
93         TDB_DATA key, data;
94
95         key.dptr = keystr;
96         key.dsize = len;
97         data.dptr = (void *)&v;
98         data.dsize = sizeof(int);
99
100         return tdb_store(tdb, key, data, TDB_REPLACE);
101 }
102
103 /****************************************************************************
104  Store a value by string key, return 0 on success, -1 on failure.
105  JRA. DEPRECATED ! Use tdb_store_int32 instead.
106 ****************************************************************************/
107
108 int tdb_store_int(TDB_CONTEXT *tdb, char *keystr, int v)
109 {
110         return tdb_store_int_byblob(tdb, keystr, strlen(keystr) + 1, v);
111 }
112
113 /****************************************************************************
114  Fetch a int32 value by a arbitrary blob key, return -1 if not found.
115  Output is int32 in native byte order.
116 ****************************************************************************/
117
118 int32 tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, char *keyval, size_t len)
119 {
120         TDB_DATA key, data;
121         int32 ret;
122
123         key.dptr = keyval;
124         key.dsize = len;
125         data = tdb_fetch(tdb, key);
126         if (!data.dptr || data.dsize != sizeof(int32))
127                 return -1;
128         
129         ret = IVAL(data.dptr,0);
130         SAFE_FREE(data.dptr);
131         return ret;
132 }
133
134 /****************************************************************************
135  Fetch a int32 value by string key, return -1 if not found.
136  Output is int32 in native byte order.
137 ****************************************************************************/
138
139 int32 tdb_fetch_int32(TDB_CONTEXT *tdb, char *keystr)
140 {
141         return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1);
142 }
143
144 /****************************************************************************
145  Store a int32 value by an arbitary blob 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_byblob(TDB_CONTEXT *tdb, char *keystr, size_t len, int32 v)
150 {
151         TDB_DATA key, data;
152         int32 v_store;
153
154         key.dptr = keystr;
155         key.dsize = len;
156         SIVAL(&v_store,0,v);
157         data.dptr = (void *)&v_store;
158         data.dsize = sizeof(int32);
159
160         return tdb_store(tdb, key, data, TDB_REPLACE);
161 }
162
163 /****************************************************************************
164  Store a int32 value by string key, return 0 on success, -1 on failure.
165  Input is int32 in native byte order. Output in tdb is in little-endian.
166 ****************************************************************************/
167
168 int tdb_store_int32(TDB_CONTEXT *tdb, char *keystr, int32 v)
169 {
170         return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v);
171 }
172
173 /****************************************************************************
174  Store a buffer by a null terminated string key.  Return 0 on success, -1
175  on failure.
176 ****************************************************************************/
177
178 int tdb_store_by_string(TDB_CONTEXT *tdb, char *keystr, void *buffer, int len)
179 {
180     TDB_DATA key, data;
181
182     key.dptr = keystr;
183     key.dsize = strlen(keystr) + 1;
184
185     data.dptr = buffer;
186     data.dsize = len;
187
188     return tdb_store(tdb, key, data, TDB_REPLACE);
189 }
190
191 /****************************************************************************
192  Fetch a buffer using a null terminated string key.  Don't forget to call
193  free() on the result dptr.
194 ****************************************************************************/
195
196 TDB_DATA tdb_fetch_by_string(TDB_CONTEXT *tdb, char *keystr)
197 {
198     TDB_DATA key;
199
200     key.dptr = keystr;
201     key.dsize = strlen(keystr) + 1;
202
203     return tdb_fetch(tdb, key);
204 }
205
206 /****************************************************************************
207  Atomic integer change. Returns old value. To create, set initial value in *oldval. 
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  Useful pair of routines for packing/unpacking data consisting of
242  integers and strings.
243 ****************************************************************************/
244
245 size_t tdb_pack(char *buf, int bufsize, char *fmt, ...)
246 {
247         va_list ap;
248         uint16 w;
249         uint32 d;
250         int i;
251         void *p;
252         int len;
253         char *s;
254         char c;
255         char *buf0 = buf;
256         char *fmt0 = fmt;
257         int bufsize0 = bufsize;
258
259         va_start(ap, fmt);
260
261         while (*fmt) {
262                 switch ((c = *fmt++)) {
263                 case 'w':
264                         len = 2;
265                         w = (uint16)va_arg(ap, int);
266                         if (bufsize >= len)
267                                 SSVAL(buf, 0, w);
268                         break;
269                 case 'd':
270                         len = 4;
271                         d = va_arg(ap, uint32);
272                         if (bufsize >= len)
273                                 SIVAL(buf, 0, d);
274                         break;
275                 case 'p':
276                         len = 4;
277                         p = va_arg(ap, void *);
278                         d = p?1:0;
279                         if (bufsize >= len)
280                                 SIVAL(buf, 0, d);
281                         break;
282                 case 'P':
283                         s = va_arg(ap,char *);
284                         w = strlen(s);
285                         len = w + 1;
286                         if (bufsize >= len)
287                                 memcpy(buf, s, len);
288                         break;
289                 case 'f':
290                         s = va_arg(ap,char *);
291                         w = strlen(s);
292                         len = w + 1;
293                         if (bufsize >= len)
294                                 memcpy(buf, s, len);
295                         break;
296                 case 'B':
297                         i = va_arg(ap, int);
298                         s = va_arg(ap, char *);
299                         len = 4+i;
300                         if (bufsize >= len) {
301                                 SIVAL(buf, 0, i);
302                                 memcpy(buf+4, s, i);
303                         }
304                         break;
305                 default:
306                         DEBUG(0,("Unknown tdb_pack format %c in %s\n", 
307                                  c, fmt));
308                         len = 0;
309                         break;
310                 }
311
312                 buf += len;
313                 bufsize -= len;
314         }
315
316         va_end(ap);
317
318         DEBUG(18,("tdb_pack(%s, %d) -> %d\n", 
319                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
320         
321         return PTR_DIFF(buf, buf0);
322 }
323
324 /****************************************************************************
325  Useful pair of routines for packing/unpacking data consisting of
326  integers and strings.
327 ****************************************************************************/
328
329 int tdb_unpack(char *buf, int bufsize, char *fmt, ...)
330 {
331         va_list ap;
332         uint16 *w;
333         uint32 *d;
334         int len;
335         int *i;
336         void **p;
337         char *s, **b;
338         char c;
339         char *buf0 = buf;
340         char *fmt0 = fmt;
341         int bufsize0 = bufsize;
342
343         va_start(ap, fmt);
344         
345         while (*fmt) {
346                 switch ((c=*fmt++)) {
347                 case 'w':
348                         len = 2;
349                         w = va_arg(ap, uint16 *);
350                         if (bufsize < len)
351                                 goto no_space;
352                         *w = SVAL(buf, 0);
353                         break;
354                 case 'd':
355                         len = 4;
356                         d = va_arg(ap, uint32 *);
357                         if (bufsize < len)
358                                 goto no_space;
359                         *d = IVAL(buf, 0);
360                         break;
361                 case 'p':
362                         len = 4;
363                         p = va_arg(ap, void **);
364                         if (bufsize < len)
365                                 goto no_space;
366                         *p = (void *)IVAL(buf, 0);
367                         break;
368                 case 'P':
369                         s = va_arg(ap,char *);
370                         len = strlen(buf) + 1;
371                         if (bufsize < len || len > sizeof(pstring))
372                                 goto no_space;
373                         memcpy(s, buf, len);
374                         break;
375                 case 'f':
376                         s = va_arg(ap,char *);
377                         len = strlen(buf) + 1;
378                         if (bufsize < len || len > sizeof(fstring))
379                                 goto no_space;
380                         memcpy(s, buf, len);
381                         break;
382                 case 'B':
383                         i = va_arg(ap, int *);
384                         b = va_arg(ap, char **);
385                         len = 4;
386                         if (bufsize < len)
387                                 goto no_space;
388                         *i = IVAL(buf, 0);
389                         if (! *i) {
390                                 *b = NULL;
391                                 break;
392                         }
393                         len += *i;
394                         if (bufsize < len)
395                                 goto no_space;
396                         *b = (char *)malloc(*i);
397                         if (! *b)
398                                 goto no_space;
399                         memcpy(*b, buf+4, *i);
400                         break;
401                 default:
402                         DEBUG(0,("Unknown tdb_unpack format %c in %s\n", 
403                                  c, fmt));
404
405                         len = 0;
406                         break;
407                 }
408
409                 buf += len;
410                 bufsize -= len;
411         }
412
413         va_end(ap);
414
415         DEBUG(18,("tdb_unpack(%s, %d) -> %d\n", 
416                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
417
418         return PTR_DIFF(buf, buf0);
419
420  no_space:
421         return -1;
422 }
423
424 /****************************************************************************
425  Log tdb messages via DEBUG().
426 ****************************************************************************/
427
428 static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
429 {
430         va_list ap;
431         char *ptr = NULL;
432
433         va_start(ap, format);
434         vasprintf(&ptr, format, ap);
435         va_end(ap);
436         
437         if (!ptr || !*ptr)
438                 return;
439
440         DEBUG(level, ("tdb(%s): %s", tdb->name, ptr));
441         SAFE_FREE(ptr);
442 }
443
444 /****************************************************************************
445  Like tdb_open() but also setup a logging function that redirects to
446  the samba DEBUG() system.
447 ****************************************************************************/
448
449 TDB_CONTEXT *tdb_open_log(char *name, int hash_size, int tdb_flags,
450                           int open_flags, mode_t mode)
451 {
452         TDB_CONTEXT *tdb;
453
454         if (!lp_use_mmap())
455                 tdb_flags |= TDB_NOMMAP;
456
457         tdb = tdb_open(name, hash_size, tdb_flags, 
458                                     open_flags, mode);
459         if (!tdb)
460                 return NULL;
461
462         tdb_logging_function(tdb, tdb_log);
463
464         return tdb;
465 }
466
467
468 /****************************************************************************
469  Allow tdb_delete to be used as a tdb_traversal_fn.
470 ****************************************************************************/
471
472 int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
473                      void *state)
474 {
475     return tdb_delete(the_tdb, key);
476 }