]> git.samba.org - mat/samba.git/blob - source3/lib/util_tdb.c
util_tdb: add function tdb_data_string()
[mat/samba.git] / source3 / lib / util_tdb.c
1 /* 
2    Unix SMB/CIFS implementation.
3    tdb utility functions
4    Copyright (C) Andrew Tridgell   1992-1998
5    Copyright (C) Rafal Szczesniak  2002
6    Copyright (C) Michael Adam      2007
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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include "util_tdb.h"
25 #include "cbuf.h"
26
27 #undef malloc
28 #undef realloc
29 #undef calloc
30 #undef strdup
31
32 /* these are little tdb utility functions that are meant to make
33    dealing with a tdb database a little less cumbersome in Samba */
34
35 int tdb_trans_store_bystring(TDB_CONTEXT *tdb, const char *keystr,
36                              TDB_DATA data, int flags)
37 {
38         TDB_DATA key = string_term_tdb_data(keystr);
39
40         return tdb_trans_store(tdb, key, data, flags);
41 }
42
43 /****************************************************************************
44  Useful pair of routines for packing/unpacking data consisting of
45  integers and strings.
46 ****************************************************************************/
47
48 static size_t tdb_pack_va(uint8 *buf, int bufsize, const char *fmt, va_list ap)
49 {
50         uint8 bt;
51         uint16 w;
52         uint32 d;
53         int i;
54         void *p;
55         int len;
56         char *s;
57         char c;
58         uint8 *buf0 = buf;
59         const char *fmt0 = fmt;
60         int bufsize0 = bufsize;
61
62         while (*fmt) {
63                 switch ((c = *fmt++)) {
64                 case 'b': /* unsigned 8-bit integer */
65                         len = 1;
66                         bt = (uint8)va_arg(ap, int);
67                         if (bufsize && bufsize >= len)
68                                 SSVAL(buf, 0, bt);
69                         break;
70                 case 'w': /* unsigned 16-bit integer */
71                         len = 2;
72                         w = (uint16)va_arg(ap, int);
73                         if (bufsize && bufsize >= len)
74                                 SSVAL(buf, 0, w);
75                         break;
76                 case 'd': /* signed 32-bit integer (standard int in most systems) */
77                         len = 4;
78                         d = va_arg(ap, uint32);
79                         if (bufsize && bufsize >= len)
80                                 SIVAL(buf, 0, d);
81                         break;
82                 case 'p': /* pointer */
83                         len = 4;
84                         p = va_arg(ap, void *);
85                         d = p?1:0;
86                         if (bufsize && bufsize >= len)
87                                 SIVAL(buf, 0, d);
88                         break;
89                 case 'P': /* null-terminated string */
90                         s = va_arg(ap,char *);
91                         w = strlen(s);
92                         len = w + 1;
93                         if (bufsize && bufsize >= len)
94                                 memcpy(buf, s, len);
95                         break;
96                 case 'f': /* null-terminated string */
97                         s = va_arg(ap,char *);
98                         w = strlen(s);
99                         len = w + 1;
100                         if (bufsize && bufsize >= len)
101                                 memcpy(buf, s, len);
102                         break;
103                 case 'B': /* fixed-length string */
104                         i = va_arg(ap, int);
105                         s = va_arg(ap, char *);
106                         len = 4+i;
107                         if (bufsize && bufsize >= len) {
108                                 SIVAL(buf, 0, i);
109                                 memcpy(buf+4, s, i);
110                         }
111                         break;
112                 default:
113                         DEBUG(0,("Unknown tdb_pack format %c in %s\n", 
114                                  c, fmt));
115                         len = 0;
116                         break;
117                 }
118
119                 buf += len;
120                 if (bufsize)
121                         bufsize -= len;
122                 if (bufsize < 0)
123                         bufsize = 0;
124         }
125
126         DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n", 
127                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
128
129         return PTR_DIFF(buf, buf0);
130 }
131
132 size_t tdb_pack(uint8 *buf, int bufsize, const char *fmt, ...)
133 {
134         va_list ap;
135         size_t result;
136
137         va_start(ap, fmt);
138         result = tdb_pack_va(buf, bufsize, fmt, ap);
139         va_end(ap);
140         return result;
141 }
142
143 bool tdb_pack_append(TALLOC_CTX *mem_ctx, uint8 **buf, size_t *len,
144                      const char *fmt, ...)
145 {
146         va_list ap;
147         size_t len1, len2;
148
149         va_start(ap, fmt);
150         len1 = tdb_pack_va(NULL, 0, fmt, ap);
151         va_end(ap);
152
153         if (mem_ctx != NULL) {
154                 *buf = talloc_realloc(mem_ctx, *buf, uint8,
155                                             (*len) + len1);
156         } else {
157                 *buf = SMB_REALLOC_ARRAY(*buf, uint8, (*len) + len1);
158         }
159
160         if (*buf == NULL) {
161                 return False;
162         }
163
164         va_start(ap, fmt);
165         len2 = tdb_pack_va((*buf)+(*len), len1, fmt, ap);
166         va_end(ap);
167
168         if (len1 != len2) {
169                 return False;
170         }
171
172         *len += len2;
173
174         return True;
175 }
176
177 /****************************************************************************
178  Useful pair of routines for packing/unpacking data consisting of
179  integers and strings.
180 ****************************************************************************/
181
182 int tdb_unpack(const uint8 *buf, int bufsize, const char *fmt, ...)
183 {
184         va_list ap;
185         uint8 *bt;
186         uint16 *w;
187         uint32 *d;
188         int len;
189         int *i;
190         void **p;
191         char *s, **b, **ps;
192         char c;
193         const uint8 *buf0 = buf;
194         const char *fmt0 = fmt;
195         int bufsize0 = bufsize;
196
197         va_start(ap, fmt);
198
199         while (*fmt) {
200                 switch ((c=*fmt++)) {
201                 case 'b': /* unsigned 8-bit integer */
202                         len = 1;
203                         bt = va_arg(ap, uint8 *);
204                         if (bufsize < len)
205                                 goto no_space;
206                         *bt = SVAL(buf, 0);
207                         break;
208                 case 'w': /* unsigned 16-bit integer */
209                         len = 2;
210                         w = va_arg(ap, uint16 *);
211                         if (bufsize < len)
212                                 goto no_space;
213                         *w = SVAL(buf, 0);
214                         break;
215                 case 'd': /* unsigned 32-bit integer (standard int in most systems) */
216                         len = 4;
217                         d = va_arg(ap, uint32 *);
218                         if (bufsize < len)
219                                 goto no_space;
220                         *d = IVAL(buf, 0);
221                         break;
222                 case 'p': /* pointer */
223                         len = 4;
224                         p = va_arg(ap, void **);
225                         if (bufsize < len)
226                                 goto no_space;
227                         /*
228                          * This isn't a real pointer - only a token (1 or 0)
229                          * to mark the fact a pointer is present.
230                          */
231
232                         *p = (void *)(IVAL(buf, 0) ? (void *)1 : NULL);
233                         break;
234                 case 'P': /* null-terminated string */
235                         /* Return malloc'ed string. */
236                         ps = va_arg(ap,char **);
237                         len = strnlen((const char *)buf, bufsize) + 1;
238                         if (bufsize < len)
239                                 goto no_space;
240                         *ps = SMB_STRDUP((const char *)buf);
241                         if (*ps == NULL) {
242                                 goto no_space;
243                         }
244                         break;
245                 case 'f': /* null-terminated string */
246                         s = va_arg(ap,char *);
247                         len = strnlen((const char *)buf, bufsize) + 1;
248                         if (bufsize < len || len > sizeof(fstring))
249                                 goto no_space;
250                         memcpy(s, buf, len);
251                         break;
252                 case 'B': /* fixed-length string */
253                         i = va_arg(ap, int *);
254                         b = va_arg(ap, char **);
255                         len = 4;
256                         if (bufsize < len)
257                                 goto no_space;
258                         *i = IVAL(buf, 0);
259                         if (! *i) {
260                                 *b = NULL;
261                                 break;
262                         }
263                         len += *i;
264                         if (bufsize < len)
265                                 goto no_space;
266                         *b = (char *)SMB_MALLOC(*i);
267                         if (! *b)
268                                 goto no_space;
269                         memcpy(*b, buf+4, *i);
270                         break;
271                 default:
272                         DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
273                                  c, fmt));
274
275                         len = 0;
276                         break;
277                 }
278
279                 buf += len;
280                 bufsize -= len;
281         }
282
283         va_end(ap);
284
285         DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
286                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
287
288         return PTR_DIFF(buf, buf0);
289
290  no_space:
291         va_end(ap);
292         return -1;
293 }
294
295
296 /****************************************************************************
297  Log tdb messages via DEBUG().
298 ****************************************************************************/
299
300 static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
301 {
302         va_list ap;
303         char *ptr = NULL;
304         int ret;
305
306         va_start(ap, format);
307         ret = vasprintf(&ptr, format, ap);
308         va_end(ap);
309
310         if ((ret == -1) || !*ptr)
311                 return;
312
313         DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
314         SAFE_FREE(ptr);
315 }
316
317 /****************************************************************************
318  Like tdb_open() but also setup a logging function that redirects to
319  the samba DEBUG() system.
320 ****************************************************************************/
321
322 TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
323                           int open_flags, mode_t mode)
324 {
325         TDB_CONTEXT *tdb;
326
327         if (!lp_use_mmap())
328                 tdb_flags |= TDB_NOMMAP;
329
330         if ((hash_size == 0) && (name != NULL)) {
331                 const char *base = strrchr_m(name, '/');
332                 if (base != NULL) {
333                         base += 1;
334                 }
335                 else {
336                         base = name;
337                 }
338                 hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
339         }
340
341         tdb = tdb_open_compat(name, hash_size, tdb_flags,
342                               open_flags, mode, tdb_log, NULL);
343         if (!tdb)
344                 return NULL;
345
346         return tdb;
347 }
348
349 /****************************************************************************
350  tdb_store, wrapped in a transaction. This way we make sure that a process
351  that dies within writing does not leave a corrupt tdb behind.
352 ****************************************************************************/
353
354 int tdb_trans_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
355                     int flag)
356 {
357         int res;
358
359         if ((res = tdb_transaction_start(tdb)) != 0) {
360                 DEBUG(5, ("tdb_transaction_start failed\n"));
361                 return res;
362         }
363
364         if ((res = tdb_store(tdb, key, dbuf, flag)) != 0) {
365                 DEBUG(10, ("tdb_store failed\n"));
366                 tdb_transaction_cancel(tdb);
367                 return res;
368         }
369
370         if ((res = tdb_transaction_commit(tdb)) != 0) {
371                 DEBUG(5, ("tdb_transaction_commit failed\n"));
372         }
373
374         return res;
375 }
376
377 /****************************************************************************
378  tdb_delete, wrapped in a transaction. This way we make sure that a process
379  that dies within deleting does not leave a corrupt tdb behind.
380 ****************************************************************************/
381
382 int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key)
383 {
384         int res;
385
386         if ((res = tdb_transaction_start(tdb)) != 0) {
387                 DEBUG(5, ("tdb_transaction_start failed\n"));
388                 return res;
389         }
390
391         if ((res = tdb_delete(tdb, key)) != 0) {
392                 DEBUG(10, ("tdb_delete failed\n"));
393                 tdb_transaction_cancel(tdb);
394                 return res;
395         }
396
397         if ((res = tdb_transaction_commit(tdb)) != 0) {
398                 DEBUG(5, ("tdb_transaction_commit failed\n"));
399         }
400
401         return res;
402 }
403
404 int tdb_data_cmp(TDB_DATA t1, TDB_DATA t2)
405 {
406         int ret;
407         if (t1.dptr == NULL && t2.dptr != NULL) {
408                 return -1;
409         }
410         if (t1.dptr != NULL && t2.dptr == NULL) {
411                 return 1;
412         }
413         if (t1.dptr == t2.dptr) {
414                 return t1.dsize - t2.dsize;
415         }
416         ret = memcmp(t1.dptr, t2.dptr, MIN(t1.dsize, t2.dsize));
417         if (ret == 0) {
418                 return t1.dsize - t2.dsize;
419         }
420         return ret;
421 }
422
423 char *tdb_data_string(TALLOC_CTX *mem_ctx, TDB_DATA d)
424 {
425         int len;
426         char *ret = NULL;
427         cbuf *ost = cbuf_new(mem_ctx);
428
429         if (ost == NULL) {
430                 return NULL;
431         }
432
433         len = cbuf_printf(ost, "%d:");
434         if (len == -1) {
435                 goto done;
436         }
437
438         if (d.dptr == NULL) {
439                 len = cbuf_puts(ost, "<NULL>", -1);
440         } else {
441                 len = cbuf_print_quoted(ost, (const char*)d.dptr, d.dsize);
442         }
443         if (len == -1) {
444                 goto done;
445         }
446
447         cbuf_swapptr(ost, &ret, 0);
448         talloc_steal(mem_ctx, ret);
449
450 done:
451         talloc_free(ost);
452         return ret;
453 }