1 /*
2 Unix SMB/CIFS implementation.
3
4 tdb utility functions
5
6 Copyright (C) Andrew Tridgell 1992-2006
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "lib/tdb/include/tdb.h"
25 #include "pstring.h"
26
27 /* these are little tdb utility functions that are meant to make
28 dealing with a tdb database a little less cumbersome in Samba */
29
30 /***************************************************************
31 Make a TDB_DATA and keep the const warning in one place
32 ****************************************************************/
33
make_tdb_data(const char * dptr,size_t dsize)34 static TDB_DATA make_tdb_data(const char *dptr, size_t dsize)
35 {
36 TDB_DATA ret;
37 ret.dptr = discard_const_p(unsigned char, dptr);
38 ret.dsize = dsize;
39 return ret;
40 }
41
42 /****************************************************************************
43 Lock a chain by string. Return -1 if lock failed.
44 ****************************************************************************/
45
tdb_lock_bystring(struct tdb_context * tdb,const char * keyval)46 int tdb_lock_bystring(struct tdb_context *tdb, const char *keyval)
47 {
48 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
49
50 return tdb_chainlock(tdb, key);
51 }
52
53 /****************************************************************************
54 Unlock a chain by string.
55 ****************************************************************************/
56
tdb_unlock_bystring(struct tdb_context * tdb,const char * keyval)57 void tdb_unlock_bystring(struct tdb_context *tdb, const char *keyval)
58 {
59 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
60
61 tdb_chainunlock(tdb, key);
62 }
63
64 /****************************************************************************
65 Read lock a chain by string. Return -1 if lock failed.
66 ****************************************************************************/
67
tdb_read_lock_bystring(struct tdb_context * tdb,const char * keyval)68 int tdb_read_lock_bystring(struct tdb_context *tdb, const char *keyval)
69 {
70 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
71
72 return tdb_chainlock_read(tdb, key);
73 }
74
75 /****************************************************************************
76 Read unlock a chain by string.
77 ****************************************************************************/
78
tdb_read_unlock_bystring(struct tdb_context * tdb,const char * keyval)79 void tdb_read_unlock_bystring(struct tdb_context *tdb, const char *keyval)
80 {
81 TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
82
83 tdb_chainunlock_read(tdb, key);
84 }
85
86
87 /****************************************************************************
88 Fetch a int32_t value by a arbitrary blob key, return -1 if not found.
89 Output is int32_t in native byte order.
90 ****************************************************************************/
91
tdb_fetch_int32_byblob(struct tdb_context * tdb,const char * keyval,size_t len)92 int32_t tdb_fetch_int32_byblob(struct tdb_context *tdb, const char *keyval, size_t len)
93 {
94 TDB_DATA key = make_tdb_data(keyval, len);
95 TDB_DATA data;
96 int32_t ret;
97
98 data = tdb_fetch(tdb, key);
99 if (!data.dptr || data.dsize != sizeof(int32_t)) {
100 SAFE_FREE(data.dptr);
101 return -1;
102 }
103
104 ret = IVAL(data.dptr,0);
105 SAFE_FREE(data.dptr);
106 return ret;
107 }
108
109 /****************************************************************************
110 Fetch a int32_t value by string key, return -1 if not found.
111 Output is int32_t in native byte order.
112 ****************************************************************************/
113
tdb_fetch_int32(struct tdb_context * tdb,const char * keystr)114 int32_t tdb_fetch_int32(struct tdb_context *tdb, const char *keystr)
115 {
116 return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1);
117 }
118
119 /****************************************************************************
120 Store a int32_t value by an arbitary blob key, return 0 on success, -1 on failure.
121 Input is int32_t in native byte order. Output in tdb is in little-endian.
122 ****************************************************************************/
123
tdb_store_int32_byblob(struct tdb_context * tdb,const char * keystr,size_t len,int32_t v)124 int tdb_store_int32_byblob(struct tdb_context *tdb, const char *keystr, size_t len, int32_t v)
125 {
126 TDB_DATA key = make_tdb_data(keystr, len);
127 TDB_DATA data;
128 int32_t v_store;
129
130 SIVAL(&v_store,0,v);
131 data.dptr = (void *)&v_store;
132 data.dsize = sizeof(int32_t);
133
134 return tdb_store(tdb, key, data, TDB_REPLACE);
135 }
136
137 /****************************************************************************
138 Store a int32_t value by string key, return 0 on success, -1 on failure.
139 Input is int32_t in native byte order. Output in tdb is in little-endian.
140 ****************************************************************************/
141
tdb_store_int32(struct tdb_context * tdb,const char * keystr,int32_t v)142 int tdb_store_int32(struct tdb_context *tdb, const char *keystr, int32_t v)
143 {
144 return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v);
145 }
146
147 /****************************************************************************
148 Fetch a uint32_t value by a arbitrary blob key, return -1 if not found.
149 Output is uint32_t in native byte order.
150 ****************************************************************************/
151
tdb_fetch_uint32_byblob(struct tdb_context * tdb,const char * keyval,size_t len,uint32_t * value)152 BOOL tdb_fetch_uint32_byblob(struct tdb_context *tdb, const char *keyval, size_t len, uint32_t *value)
153 {
154 TDB_DATA key = make_tdb_data(keyval, len);
155 TDB_DATA data;
156
157 data = tdb_fetch(tdb, key);
158 if (!data.dptr || data.dsize != sizeof(uint32_t)) {
159 SAFE_FREE(data.dptr);
160 return False;
161 }
162
163 *value = IVAL(data.dptr,0);
164 SAFE_FREE(data.dptr);
165 return True;
166 }
167
168 /****************************************************************************
169 Fetch a uint32_t value by string key, return -1 if not found.
170 Output is uint32_t in native byte order.
171 ****************************************************************************/
172
tdb_fetch_uint32(struct tdb_context * tdb,const char * keystr,uint32_t * value)173 BOOL tdb_fetch_uint32(struct tdb_context *tdb, const char *keystr, uint32_t *value)
174 {
175 return tdb_fetch_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
176 }
177
178 /****************************************************************************
179 Store a uint32_t value by an arbitary blob key, return 0 on success, -1 on failure.
180 Input is uint32_t in native byte order. Output in tdb is in little-endian.
181 ****************************************************************************/
182
tdb_store_uint32_byblob(struct tdb_context * tdb,const char * keystr,size_t len,uint32_t value)183 BOOL tdb_store_uint32_byblob(struct tdb_context *tdb, const char *keystr, size_t len, uint32_t value)
184 {
185 TDB_DATA key = make_tdb_data(keystr, len);
186 TDB_DATA data;
187 uint32_t v_store;
188 BOOL ret = True;
189
190 SIVAL(&v_store, 0, value);
191 data.dptr = (void *)&v_store;
192 data.dsize = sizeof(uint32_t);
193
194 if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
195 ret = False;
196
197 return ret;
198 }
199
200 /****************************************************************************
201 Store a uint32_t value by string key, return 0 on success, -1 on failure.
202 Input is uint32_t in native byte order. Output in tdb is in little-endian.
203 ****************************************************************************/
204
tdb_store_uint32(struct tdb_context * tdb,const char * keystr,uint32_t value)205 BOOL tdb_store_uint32(struct tdb_context *tdb, const char *keystr, uint32_t value)
206 {
207 return tdb_store_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
208 }
209 /****************************************************************************
210 Store a buffer by a null terminated string key. Return 0 on success, -1
211 on failure.
212 ****************************************************************************/
213
tdb_store_bystring(struct tdb_context * tdb,const char * keystr,TDB_DATA data,int flags)214 int tdb_store_bystring(struct tdb_context *tdb, const char *keystr, TDB_DATA data, int flags)
215 {
216 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
217
218 return tdb_store(tdb, key, data, flags);
219 }
220
221 /****************************************************************************
222 Fetch a buffer using a null terminated string key. Don't forget to call
223 free() on the result dptr.
224 ****************************************************************************/
225
tdb_fetch_bystring(struct tdb_context * tdb,const char * keystr)226 TDB_DATA tdb_fetch_bystring(struct tdb_context *tdb, const char *keystr)
227 {
228 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
229
230 return tdb_fetch(tdb, key);
231 }
232
233 /****************************************************************************
234 Delete an entry using a null terminated string key.
235 ****************************************************************************/
236
tdb_delete_bystring(struct tdb_context * tdb,const char * keystr)237 int tdb_delete_bystring(struct tdb_context *tdb, const char *keystr)
238 {
239 TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
240
241 return tdb_delete(tdb, key);
242 }
243
244 /****************************************************************************
245 Atomic integer change. Returns old value. To create, set initial value in *oldval.
246 ****************************************************************************/
247
tdb_change_int32_atomic(struct tdb_context * tdb,const char * keystr,int32_t * oldval,int32_t change_val)248 int32_t tdb_change_int32_atomic(struct tdb_context *tdb, const char *keystr, int32_t *oldval, int32_t change_val)
249 {
250 int32_t val;
251 int32_t ret = -1;
252
253 if (tdb_lock_bystring(tdb, keystr) == -1)
254 return -1;
255
256 if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
257 /* The lookup failed */
258 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
259 /* but not because it didn't exist */
260 goto err_out;
261 }
262
263 /* Start with 'old' value */
264 val = *oldval;
265
266 } else {
267 /* It worked, set return value (oldval) to tdb data */
268 *oldval = val;
269 }
270
271 /* Increment value for storage and return next time */
272 val += change_val;
273
274 if (tdb_store_int32(tdb, keystr, val) == -1)
275 goto err_out;
276
277 ret = 0;
278
279 err_out:
280
281 tdb_unlock_bystring(tdb, keystr);
282 return ret;
283 }
284
285 /****************************************************************************
286 Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
287 ****************************************************************************/
288
tdb_change_uint32_atomic(struct tdb_context * tdb,const char * keystr,uint32_t * oldval,uint32_t change_val)289 BOOL tdb_change_uint32_atomic(struct tdb_context *tdb, const char *keystr, uint32_t *oldval, uint32_t change_val)
290 {
291 uint32_t val;
292 BOOL ret = False;
293
294 if (tdb_lock_bystring(tdb, keystr) == -1)
295 return False;
296
297 if (!tdb_fetch_uint32(tdb, keystr, &val)) {
298 /* It failed */
299 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
300 /* and not because it didn't exist */
301 goto err_out;
302 }
303
304 /* Start with 'old' value */
305 val = *oldval;
306
307 } else {
308 /* it worked, set return value (oldval) to tdb data */
309 *oldval = val;
310
311 }
312
313 /* get a new value to store */
314 val += change_val;
315
316 if (!tdb_store_uint32(tdb, keystr, val))
317 goto err_out;
318
319 ret = True;
320
321 err_out:
322
323 tdb_unlock_bystring(tdb, keystr);
324 return ret;
325 }
326
327 /****************************************************************************
328 Allow tdb_delete to be used as a tdb_traversal_fn.
329 ****************************************************************************/
330
tdb_traverse_delete_fn(struct tdb_context * the_tdb,TDB_DATA key,TDB_DATA dbuf,void * state)331 int tdb_traverse_delete_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf,
332 void *state)
333 {
334 return tdb_delete(the_tdb, key);
335 }
336
337
338
339 /****************************************************************************
340 Useful pair of routines for packing/unpacking data consisting of
341 integers and strings.
342 ****************************************************************************/
343
tdb_pack(TDB_CONTEXT * tdb,char * buf,int bufsize,const char * fmt,...)344 size_t tdb_pack(TDB_CONTEXT *tdb, char *buf, int bufsize, const char *fmt, ...)
345 {
346 va_list ap;
347 uint8_t bt;
348 uint16_t w;
349 uint32_t d;
350 int i;
351 void *p;
352 int len;
353 char *s;
354 char c;
355 char *buf0 = buf;
356 const char *fmt0 = fmt;
357 int bufsize0 = bufsize;
358 tdb_log_func log_fn = tdb_log_fn(tdb);
359
360 va_start(ap, fmt);
361
362 while (*fmt) {
363 switch ((c = *fmt++)) {
364 case 'b': /* unsigned 8-bit integer */
365 len = 1;
366 bt = (uint8_t)va_arg(ap, int);
367 if (bufsize && bufsize >= len)
368 SSVAL(buf, 0, bt);
369 break;
370 case 'w': /* unsigned 16-bit integer */
371 len = 2;
372 w = (uint16_t)va_arg(ap, int);
373 if (bufsize && bufsize >= len)
374 SSVAL(buf, 0, w);
375 break;
376 case 'd': /* signed 32-bit integer (standard int in most systems) */
377 len = 4;
378 d = va_arg(ap, uint32_t);
379 if (bufsize && bufsize >= len)
380 SIVAL(buf, 0, d);
381 break;
382 case 'p': /* pointer */
383 len = 4;
384 p = va_arg(ap, void *);
385 d = p?1:0;
386 if (bufsize && bufsize >= len)
387 SIVAL(buf, 0, d);
388 break;
389 case 'P': /* null-terminated string */
390 s = va_arg(ap,char *);
391 w = strlen(s);
392 len = w + 1;
393 if (bufsize && bufsize >= len)
394 memcpy(buf, s, len);
395 break;
396 case 'f': /* null-terminated string */
397 s = va_arg(ap,char *);
398 w = strlen(s);
399 len = w + 1;
400 if (bufsize && bufsize >= len)
401 memcpy(buf, s, len);
402 break;
403 case 'B': /* fixed-length string */
404 i = va_arg(ap, int);
405 s = va_arg(ap, char *);
406 len = 4+i;
407 if (bufsize && bufsize >= len) {
408 SIVAL(buf, 0, i);
409 memcpy(buf+4, s, i);
410 }
411 break;
412 default:
413 log_fn(tdb, 0,"Unknown tdb_pack format %c in %s\n",
414 c, fmt);
415 len = 0;
416 break;
417 }
418
419 buf += len;
420 if (bufsize)
421 bufsize -= len;
422 if (bufsize < 0)
423 bufsize = 0;
424 }
425
426 va_end(ap);
427
428 log_fn(tdb, 18,"tdb_pack(%s, %d) -> %d\n",
429 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0));
430
431 return PTR_DIFF(buf, buf0);
432 }
433
434 /****************************************************************************
435 Useful pair of routines for packing/unpacking data consisting of
436 integers and strings.
437 ****************************************************************************/
438
tdb_unpack(TDB_CONTEXT * tdb,char * buf,int bufsize,const char * fmt,...)439 int tdb_unpack(TDB_CONTEXT *tdb, char *buf, int bufsize, const char *fmt, ...)
440 {
441 va_list ap;
442 uint8_t *bt;
443 uint16_t *w;
444 uint32_t *d;
445 int len;
446 int *i;
447 void **p;
448 char *s, **b;
449 char c;
450 char *buf0 = buf;
451 const char *fmt0 = fmt;
452 int bufsize0 = bufsize;
453 tdb_log_func log_fn = tdb_log_fn(tdb);
454
455 va_start(ap, fmt);
456
457 while (*fmt) {
458 switch ((c=*fmt++)) {
459 case 'b':
460 len = 1;
461 bt = va_arg(ap, uint8_t *);
462 if (bufsize < len)
463 goto no_space;
464 *bt = SVAL(buf, 0);
465 break;
466 case 'w':
467 len = 2;
468 w = va_arg(ap, uint16_t *);
469 if (bufsize < len)
470 goto no_space;
471 *w = SVAL(buf, 0);
472 break;
473 case 'd':
474 len = 4;
475 d = va_arg(ap, uint32_t *);
476 if (bufsize < len)
477 goto no_space;
478 *d = IVAL(buf, 0);
479 break;
480 case 'p':
481 len = 4;
482 p = va_arg(ap, void **);
483 if (bufsize < len)
484 goto no_space;
485 *p = (void *)IVAL(buf, 0);
486 break;
487 case 'P':
488 s = va_arg(ap,char *);
489 len = strlen(buf) + 1;
490 if (bufsize < len || len > sizeof(pstring))
491 goto no_space;
492 memcpy(s, buf, len);
493 break;
494 case 'f':
495 s = va_arg(ap,char *);
496 len = strlen(buf) + 1;
497 if (bufsize < len || len > sizeof(fstring))
498 goto no_space;
499 memcpy(s, buf, len);
500 break;
501 case 'B':
502 i = va_arg(ap, int *);
503 b = va_arg(ap, char **);
504 len = 4;
505 if (bufsize < len)
506 goto no_space;
507 *i = IVAL(buf, 0);
508 if (! *i) {
509 *b = NULL;
510 break;
511 }
512 len += *i;
513 if (bufsize < len)
514 goto no_space;
515 *b = (char *)malloc(*i);
516 if (! *b)
517 goto no_space;
518 memcpy(*b, buf+4, *i);
519 break;
520 default:
521 log_fn(tdb, 0, "Unknown tdb_unpack format %c in %s\n",
522 c, fmt);
523
524 len = 0;
525 break;
526 }
527
528 buf += len;
529 bufsize -= len;
530 }
531
532 va_end(ap);
533
534 log_fn(tdb, 18, "tdb_unpack(%s, %d) -> %d\n",
535 fmt0, bufsize0, (int)PTR_DIFF(buf, buf0));
536
537 return PTR_DIFF(buf, buf0);
538
539 no_space:
540 return -1;
541 }
542