always compile before commit :-)
[Samba.git] / source / tdb / tdbutil.c
blob0a2f1f84d458a6e438e5d53d7d83db1a6a8d0822
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 tdb utility functions
5 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
22 #include "includes.h"
24 /* these are little tdb utility functions that are meant to make
25 dealing with a tdb database a little less cumbersome in Samba */
27 /* lock a chain by string */
28 int tdb_lock_bystring(TDB_CONTEXT *tdb, char *keyval)
30 TDB_DATA key;
32 key.dptr = keyval;
33 key.dsize = strlen(keyval)+1;
35 return tdb_chainlock(tdb, key);
38 /* unlock a chain by string */
39 void tdb_unlock_bystring(TDB_CONTEXT *tdb, char *keyval)
41 TDB_DATA key;
43 key.dptr = keyval;
44 key.dsize = strlen(keyval)+1;
46 tdb_chainunlock(tdb, key);
49 /* fetch a value by a arbitrary blob key, return -1 if not found */
50 int tdb_fetch_int_byblob(TDB_CONTEXT *tdb, char *keyval, size_t len)
52 TDB_DATA key, data;
53 int ret;
55 key.dptr = keyval;
56 key.dsize = len;
57 data = tdb_fetch(tdb, key);
58 if (!data.dptr || data.dsize != sizeof(int)) return -1;
60 memcpy(&ret, data.dptr, sizeof(int));
61 free(data.dptr);
62 return ret;
65 /* fetch a value by string key, return -1 if not found */
66 int tdb_fetch_int(TDB_CONTEXT *tdb, char *keystr)
68 return tdb_fetch_int_byblob(tdb, keystr, strlen(keystr) + 1);
71 /* store a value by an arbitary blob key, return 0 on success, -1 on failure */
72 int tdb_store_int_byblob(TDB_CONTEXT *tdb, char *keystr, size_t len, int v)
74 TDB_DATA key, data;
76 key.dptr = keystr;
77 key.dsize = len;
78 data.dptr = (void *)&v;
79 data.dsize = sizeof(int);
81 return tdb_store(tdb, key, data, TDB_REPLACE);
84 /* store a value by string key, return 0 on success, -1 on failure */
85 int tdb_store_int(TDB_CONTEXT *tdb, char *keystr, int v)
87 return tdb_store_int_byblob(tdb, keystr, strlen(keystr) + 1, v);
90 /* Store a buffer by a null terminated string key. Return 0 on success, -1
91 on failure */
92 int tdb_store_by_string(TDB_CONTEXT *tdb, char *keystr, void *buffer, int len)
94 TDB_DATA key, data;
96 key.dptr = keystr;
97 key.dsize = strlen(keystr) + 1;
99 data.dptr = buffer;
100 data.dsize = len;
102 return tdb_store(tdb, key, data, TDB_REPLACE);
105 /* Fetch a buffer using a null terminated string key. Don't forget to call
106 free() on the result dptr. */
108 TDB_DATA tdb_fetch_by_string(TDB_CONTEXT *tdb, char *keystr)
110 TDB_DATA key;
112 key.dptr = keystr;
113 key.dsize = strlen(keystr) + 1;
115 return tdb_fetch(tdb, key);
118 /* Atomic integer change. Returns old value. To create, set initial value in *oldval. */
120 int tdb_change_int_atomic(TDB_CONTEXT *tdb, char *keystr, int *oldval, int change_val)
122 int val;
123 int ret = -1;
125 if (tdb_lock_bystring(tdb, keystr) == -1)
126 return -1;
128 if ((val = tdb_fetch_int(tdb, keystr)) == -1) {
129 if (tdb_error(tdb) != TDB_ERR_NOEXIST)
130 goto err_out;
132 val = *oldval;
134 } else {
135 *oldval = val;
136 val += change_val;
139 if (tdb_store_int(tdb, keystr, val) == -1)
140 goto err_out;
142 ret = 0;
144 err_out:
146 tdb_unlock_bystring(tdb, keystr);
147 return ret;
150 /* useful pair of routines for packing/unpacking data consisting of
151 integers and strings */
152 size_t tdb_pack(char *buf, int bufsize, char *fmt, ...)
154 va_list ap;
155 uint16 w;
156 uint32 d;
157 int i;
158 void *p;
159 int len;
160 char *s;
161 char c;
162 char *buf0 = buf;
163 char *fmt0 = fmt;
164 int bufsize0 = bufsize;
166 va_start(ap, fmt);
168 while (*fmt) {
169 switch ((c = *fmt++)) {
170 case 'w':
171 len = 2;
172 w = (uint16)va_arg(ap, int);
173 if (bufsize >= len) {
174 SSVAL(buf, 0, w);
176 break;
177 case 'd':
178 len = 4;
179 d = va_arg(ap, uint32);
180 if (bufsize >= len) {
181 SIVAL(buf, 0, d);
183 break;
184 case 'p':
185 len = 4;
186 p = va_arg(ap, void *);
187 d = p?1:0;
188 if (bufsize >= len) {
189 SIVAL(buf, 0, d);
191 break;
192 case 'P':
193 s = va_arg(ap,char *);
194 w = strlen(s);
195 len = w + 1;
196 if (bufsize >= len) {
197 memcpy(buf, s, len);
199 break;
200 case 'f':
201 s = va_arg(ap,char *);
202 w = strlen(s);
203 len = w + 1;
204 if (bufsize >= len) {
205 memcpy(buf, s, len);
207 break;
208 case 'B':
209 i = va_arg(ap, int);
210 s = va_arg(ap, char *);
211 len = 4+i;
212 if (bufsize >= len) {
213 SIVAL(buf, 0, i);
214 memcpy(buf+4, s, i);
216 break;
217 default:
218 DEBUG(0,("Unknown tdb_pack format %c in %s\n",
219 c, fmt));
220 len = 0;
221 break;
224 buf += len;
225 bufsize -= len;
228 va_end(ap);
230 DEBUG(8,("tdb_pack(%s, %d) -> %d\n",
231 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
233 return PTR_DIFF(buf, buf0);
238 /* useful pair of routines for packing/unpacking data consisting of
239 integers and strings */
241 int tdb_unpack(char *buf, int bufsize, char *fmt, ...)
243 va_list ap;
244 uint16 *w;
245 uint32 *d;
246 int len;
247 int *i;
248 void **p;
249 char *s, **b;
250 char c;
251 char *buf0 = buf;
252 char *fmt0 = fmt;
253 int bufsize0 = bufsize;
255 va_start(ap, fmt);
257 while (*fmt) {
258 switch ((c=*fmt++)) {
259 case 'w':
260 len = 2;
261 w = va_arg(ap, uint16 *);
262 if (bufsize < len) goto no_space;
263 *w = SVAL(buf, 0);
264 break;
265 case 'd':
266 len = 4;
267 d = va_arg(ap, uint32 *);
268 if (bufsize < len) goto no_space;
269 *d = IVAL(buf, 0);
270 break;
271 case 'p':
272 len = 4;
273 p = va_arg(ap, void **);
274 if (bufsize < len) goto no_space;
275 *p = (void *)IVAL(buf, 0);
276 break;
277 case 'P':
278 s = va_arg(ap,char *);
279 len = strlen(buf) + 1;
280 if (bufsize < len || len > sizeof(pstring)) goto no_space;
281 memcpy(s, buf, len);
282 break;
283 case 'f':
284 s = va_arg(ap,char *);
285 len = strlen(buf) + 1;
286 if (bufsize < len || len > sizeof(fstring)) goto no_space;
287 memcpy(s, buf, len);
288 break;
289 case 'B':
290 i = va_arg(ap, int *);
291 b = va_arg(ap, char **);
292 len = 4;
293 if (bufsize < len) goto no_space;
294 *i = IVAL(buf, 0);
295 if (! *i) {
296 *b = NULL;
297 break;
299 len += *i;
300 if (bufsize < len) goto no_space;
301 *b = (char *)malloc(*i);
302 if (! *b) goto no_space;
303 memcpy(*b, buf+4, *i);
304 break;
305 default:
306 DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
307 c, fmt));
309 len = 0;
310 break;
313 buf += len;
314 bufsize -= len;
317 va_end(ap);
319 DEBUG(8,("tdb_unpack(%s, %d) -> %d\n",
320 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
322 return PTR_DIFF(buf, buf0);
324 no_space:
325 return -1;
328 /****************************************************************************
329 log tdb messages via DEBUG()
330 ****************************************************************************/
331 static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
333 va_list ap;
334 char *ptr = NULL;
336 va_start(ap, format);
337 vasprintf(&ptr, format, ap);
338 va_end(ap);
340 if (!ptr || !*ptr) return;
342 DEBUG(level, ("tdb(%s): %s", tdb->name, ptr));
343 free(ptr);
348 /* like tdb_open() but also setup a logging function that redirects to
349 the samba DEBUG() system */
350 TDB_CONTEXT *tdb_open_log(char *name, int hash_size, int tdb_flags,
351 int open_flags, mode_t mode)
353 TDB_CONTEXT *tdb = tdb_open(name, hash_size, tdb_flags,
354 open_flags, mode);
355 if (!tdb) return NULL;
357 tdb_logging_function(tdb, tdb_log);
359 return tdb;