get rid of annoying "change your password now" message
[Samba.git] / source / tdb / tdbutil.c
blob5250d675c913c8016c7c11c3a0c2efb0ac333a12
1 /*
2 Unix SMB/CIFS implementation.
3 tdb utility functions
4 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
21 #include "includes.h"
23 /* these are little tdb utility functions that are meant to make
24 dealing with a tdb database a little less cumbersome in Samba */
26 /****************************************************************************
27 Lock a chain by string.
28 ****************************************************************************/
30 int tdb_lock_bystring(TDB_CONTEXT *tdb, char *keyval)
32 TDB_DATA key;
34 key.dptr = keyval;
35 key.dsize = strlen(keyval)+1;
37 return tdb_chainlock(tdb, key);
40 /****************************************************************************
41 Unlock a chain by string.
42 ****************************************************************************/
44 void tdb_unlock_bystring(TDB_CONTEXT *tdb, char *keyval)
46 TDB_DATA key;
48 key.dptr = keyval;
49 key.dsize = strlen(keyval)+1;
51 tdb_chainunlock(tdb, key);
54 /****************************************************************************
55 Fetch a int32 value by a arbitrary blob key, return -1 if not found.
56 Output is int32 in native byte order.
57 ****************************************************************************/
59 int32 tdb_fetch_int32_byblob(TDB_CONTEXT *tdb, char *keyval, size_t len)
61 TDB_DATA key, data;
62 int32 ret;
64 key.dptr = keyval;
65 key.dsize = len;
66 data = tdb_fetch(tdb, key);
67 if (!data.dptr || data.dsize != sizeof(int32))
68 return -1;
70 ret = IVAL(data.dptr,0);
71 SAFE_FREE(data.dptr);
72 return ret;
75 /****************************************************************************
76 Fetch a int32 value by string key, return -1 if not found.
77 Output is int32 in native byte order.
78 ****************************************************************************/
80 int32 tdb_fetch_int32(TDB_CONTEXT *tdb, char *keystr)
82 return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1);
85 /****************************************************************************
86 Store a int32 value by an arbitary blob key, return 0 on success, -1 on failure.
87 Input is int32 in native byte order. Output in tdb is in little-endian.
88 ****************************************************************************/
90 int tdb_store_int32_byblob(TDB_CONTEXT *tdb, char *keystr, size_t len, int32 v)
92 TDB_DATA key, data;
93 int32 v_store;
95 key.dptr = keystr;
96 key.dsize = len;
97 SIVAL(&v_store,0,v);
98 data.dptr = (void *)&v_store;
99 data.dsize = sizeof(int32);
101 return tdb_store(tdb, key, data, TDB_REPLACE);
104 /****************************************************************************
105 Store a int32 value by string key, return 0 on success, -1 on failure.
106 Input is int32 in native byte order. Output in tdb is in little-endian.
107 ****************************************************************************/
109 int tdb_store_int32(TDB_CONTEXT *tdb, char *keystr, int32 v)
111 return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v);
114 /****************************************************************************
115 Fetch a uint32 value by a arbitrary blob key, return -1 if not found.
116 Output is uint32 in native byte order.
117 ****************************************************************************/
119 BOOL tdb_fetch_uint32_byblob(TDB_CONTEXT *tdb, char *keyval, size_t len, uint32 *value)
121 TDB_DATA key, data;
123 key.dptr = keyval;
124 key.dsize = len;
125 data = tdb_fetch(tdb, key);
126 if (!data.dptr || data.dsize != sizeof(uint32))
127 return False;
129 *value = IVAL(data.dptr,0);
130 SAFE_FREE(data.dptr);
131 return True;
134 /****************************************************************************
135 Fetch a uint32 value by string key, return -1 if not found.
136 Output is uint32 in native byte order.
137 ****************************************************************************/
139 BOOL tdb_fetch_uint32(TDB_CONTEXT *tdb, char *keystr, uint32 *value)
141 return tdb_fetch_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
144 /****************************************************************************
145 Store a uint32 value by an arbitary blob key, return 0 on success, -1 on failure.
146 Input is uint32 in native byte order. Output in tdb is in little-endian.
147 ****************************************************************************/
149 BOOL tdb_store_uint32_byblob(TDB_CONTEXT *tdb, char *keystr, size_t len, uint32 value)
151 TDB_DATA key, data;
152 uint32 v_store;
153 BOOL ret = True;
155 key.dptr = keystr;
156 key.dsize = len;
157 SIVAL(&v_store, 0, value);
158 data.dptr = (void *)&v_store;
159 data.dsize = sizeof(uint32);
161 if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
162 ret = False;
164 return ret;
167 /****************************************************************************
168 Store a uint32 value by string key, return 0 on success, -1 on failure.
169 Input is uint32 in native byte order. Output in tdb is in little-endian.
170 ****************************************************************************/
172 BOOL tdb_store_uint32(TDB_CONTEXT *tdb, char *keystr, uint32 value)
174 return tdb_store_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
176 /****************************************************************************
177 Store a buffer by a null terminated string key. Return 0 on success, -1
178 on failure.
179 ****************************************************************************/
181 int tdb_store_by_string(TDB_CONTEXT *tdb, char *keystr, void *buffer, int len)
183 TDB_DATA key, data;
185 key.dptr = keystr;
186 key.dsize = strlen(keystr) + 1;
188 data.dptr = buffer;
189 data.dsize = len;
191 return tdb_store(tdb, key, data, TDB_REPLACE);
194 /****************************************************************************
195 Fetch a buffer using a null terminated string key. Don't forget to call
196 free() on the result dptr.
197 ****************************************************************************/
199 TDB_DATA tdb_fetch_by_string(TDB_CONTEXT *tdb, char *keystr)
201 TDB_DATA key;
203 key.dptr = keystr;
204 key.dsize = strlen(keystr) + 1;
206 return tdb_fetch(tdb, key);
209 /****************************************************************************
210 Atomic integer change. Returns old value. To create, set initial value in *oldval.
211 ****************************************************************************/
213 int32 tdb_change_int32_atomic(TDB_CONTEXT *tdb, char *keystr, int32 *oldval, int32 change_val)
215 int32 val;
216 int32 ret = -1;
218 if (tdb_lock_bystring(tdb, keystr) == -1)
219 return -1;
221 if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
222 /* The lookup failed */
223 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
224 /* but not becouse it didn't exist */
225 goto err_out;
228 /* Start with 'old' value */
229 val = *oldval;
231 } else {
232 /* It worked, set return value (oldval) to tdb data */
233 *oldval = val;
236 /* Increment value for storage and return next time */
237 val += change_val;
239 if (tdb_store_int32(tdb, keystr, val) == -1)
240 goto err_out;
242 ret = 0;
244 err_out:
246 tdb_unlock_bystring(tdb, keystr);
247 return ret;
250 /****************************************************************************
251 Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
252 ****************************************************************************/
254 BOOL tdb_change_uint32_atomic(TDB_CONTEXT *tdb, char *keystr, uint32 *oldval, uint32 change_val)
256 uint32 val;
257 BOOL ret = False;
259 if (tdb_lock_bystring(tdb, keystr) == -1)
260 return False;
262 if (!tdb_fetch_uint32(tdb, keystr, &val)) {
263 /* It failed */
264 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
265 /* and not becouse it didn't exist */
266 goto err_out;
269 /* Start with 'old' value */
270 val = *oldval;
272 } else {
273 /* it worked, set return value (oldval) to tdb data */
274 *oldval = val;
278 /* get a new value to store */
279 val += change_val;
281 if (!tdb_store_uint32(tdb, keystr, val))
282 goto err_out;
284 ret = True;
286 err_out:
288 tdb_unlock_bystring(tdb, keystr);
289 return ret;
292 /****************************************************************************
293 Useful pair of routines for packing/unpacking data consisting of
294 integers and strings.
295 ****************************************************************************/
297 size_t tdb_pack(char *buf, int bufsize, char *fmt, ...)
299 va_list ap;
300 uint16 w;
301 uint32 d;
302 int i;
303 void *p;
304 int len;
305 char *s;
306 char c;
307 char *buf0 = buf;
308 char *fmt0 = fmt;
309 int bufsize0 = bufsize;
311 va_start(ap, fmt);
313 while (*fmt) {
314 switch ((c = *fmt++)) {
315 case 'w':
316 len = 2;
317 w = (uint16)va_arg(ap, int);
318 if (bufsize >= len)
319 SSVAL(buf, 0, w);
320 break;
321 case 'd':
322 len = 4;
323 d = va_arg(ap, uint32);
324 if (bufsize >= len)
325 SIVAL(buf, 0, d);
326 break;
327 case 'p':
328 len = 4;
329 p = va_arg(ap, void *);
330 d = p?1:0;
331 if (bufsize >= len)
332 SIVAL(buf, 0, d);
333 break;
334 case 'P':
335 s = va_arg(ap,char *);
336 w = strlen(s);
337 len = w + 1;
338 if (bufsize >= len)
339 memcpy(buf, s, len);
340 break;
341 case 'f':
342 s = va_arg(ap,char *);
343 w = strlen(s);
344 len = w + 1;
345 if (bufsize >= len)
346 memcpy(buf, s, len);
347 break;
348 case 'B':
349 i = va_arg(ap, int);
350 s = va_arg(ap, char *);
351 len = 4+i;
352 if (bufsize >= len) {
353 SIVAL(buf, 0, i);
354 memcpy(buf+4, s, i);
356 break;
357 default:
358 DEBUG(0,("Unknown tdb_pack format %c in %s\n",
359 c, fmt));
360 len = 0;
361 break;
364 buf += len;
365 bufsize -= len;
368 va_end(ap);
370 DEBUG(18,("tdb_pack(%s, %d) -> %d\n",
371 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
373 return PTR_DIFF(buf, buf0);
376 /****************************************************************************
377 Useful pair of routines for packing/unpacking data consisting of
378 integers and strings.
379 ****************************************************************************/
381 int tdb_unpack(char *buf, int bufsize, char *fmt, ...)
383 va_list ap;
384 uint16 *w;
385 uint32 *d;
386 int len;
387 int *i;
388 void **p;
389 char *s, **b;
390 char c;
391 char *buf0 = buf;
392 char *fmt0 = fmt;
393 int bufsize0 = bufsize;
395 va_start(ap, fmt);
397 while (*fmt) {
398 switch ((c=*fmt++)) {
399 case 'w':
400 len = 2;
401 w = va_arg(ap, uint16 *);
402 if (bufsize < len)
403 goto no_space;
404 *w = SVAL(buf, 0);
405 break;
406 case 'd':
407 len = 4;
408 d = va_arg(ap, uint32 *);
409 if (bufsize < len)
410 goto no_space;
411 *d = IVAL(buf, 0);
412 break;
413 case 'p':
414 len = 4;
415 p = va_arg(ap, void **);
416 if (bufsize < len)
417 goto no_space;
418 *p = (void *)IVAL(buf, 0);
419 break;
420 case 'P':
421 s = va_arg(ap,char *);
422 len = strlen(buf) + 1;
423 if (bufsize < len || len > sizeof(pstring))
424 goto no_space;
425 memcpy(s, buf, len);
426 break;
427 case 'f':
428 s = va_arg(ap,char *);
429 len = strlen(buf) + 1;
430 if (bufsize < len || len > sizeof(fstring))
431 goto no_space;
432 memcpy(s, buf, len);
433 break;
434 case 'B':
435 i = va_arg(ap, int *);
436 b = va_arg(ap, char **);
437 len = 4;
438 if (bufsize < len)
439 goto no_space;
440 *i = IVAL(buf, 0);
441 if (! *i) {
442 *b = NULL;
443 break;
445 len += *i;
446 if (bufsize < len)
447 goto no_space;
448 *b = (char *)malloc(*i);
449 if (! *b)
450 goto no_space;
451 memcpy(*b, buf+4, *i);
452 break;
453 default:
454 DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
455 c, fmt));
457 len = 0;
458 break;
461 buf += len;
462 bufsize -= len;
465 va_end(ap);
467 DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
468 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
470 return PTR_DIFF(buf, buf0);
472 no_space:
473 return -1;
476 /****************************************************************************
477 Log tdb messages via DEBUG().
478 ****************************************************************************/
480 static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
482 va_list ap;
483 char *ptr = NULL;
485 va_start(ap, format);
486 vasprintf(&ptr, format, ap);
487 va_end(ap);
489 if (!ptr || !*ptr)
490 return;
492 DEBUG(level, ("tdb(%s): %s", tdb->name ? tdb->name : "unknown", ptr));
493 SAFE_FREE(ptr);
496 /****************************************************************************
497 Like tdb_open() but also setup a logging function that redirects to
498 the samba DEBUG() system.
499 ****************************************************************************/
501 TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
502 int open_flags, mode_t mode)
504 TDB_CONTEXT *tdb;
506 if (!lp_use_mmap())
507 tdb_flags |= TDB_NOMMAP;
509 tdb = tdb_open_ex(name, hash_size, tdb_flags,
510 open_flags, mode, tdb_log);
511 if (!tdb)
512 return NULL;
514 return tdb;
518 /****************************************************************************
519 Allow tdb_delete to be used as a tdb_traversal_fn.
520 ****************************************************************************/
522 int tdb_traverse_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
523 void *state)
525 return tdb_delete(the_tdb, key);