vfs_streams_xattr: implement all missing handle based VFS functions
[metze/samba/wip.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_t *buf, int bufsize, const char *fmt, va_list ap)
49 {
50         uint8_t bt;
51         uint16_t w;
52         uint32_t d;
53         int i;
54         void *p;
55         int len;
56         char *s;
57         char c;
58         uint8_t *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_t)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_t)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_t);
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_t *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_t **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_t,
155                                             (*len) + len1);
156         } else {
157                 *buf = SMB_REALLOC_ARRAY(*buf, uint8_t, (*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_t *buf, int bufsize, const char *fmt, ...)
183 {
184         va_list ap;
185         uint8_t *bt;
186         uint16_t *w;
187         uint32_t *d;
188         int len;
189         int *i;
190         void **p;
191         char *s, **b, **ps;
192         char c;
193         const uint8_t *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_t *);
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_t *);
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_t *);
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,
301                     const char *format, ...) PRINTF_ATTRIBUTE(3,4);
302
303 static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
304 {
305         va_list ap;
306         char *ptr = NULL;
307         int ret;
308
309         va_start(ap, format);
310         ret = vasprintf(&ptr, format, ap);
311         va_end(ap);
312
313         if ((ret == -1) || !*ptr)
314                 return;
315
316         DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
317         SAFE_FREE(ptr);
318 }
319
320 /****************************************************************************
321  Like tdb_open() but also setup a logging function that redirects to
322  the samba DEBUG() system.
323 ****************************************************************************/
324
325 TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
326                           int open_flags, mode_t mode)
327 {
328         TDB_CONTEXT *tdb;
329         struct tdb_logging_context log_ctx = { .log_fn = tdb_log };
330
331         if (!lp_use_mmap())
332                 tdb_flags |= TDB_NOMMAP;
333
334         if ((hash_size == 0) && (name != NULL)) {
335                 const char *base = strrchr_m(name, '/');
336                 if (base != NULL) {
337                         base += 1;
338                 }
339                 else {
340                         base = name;
341                 }
342                 hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
343         }
344
345         tdb = tdb_open_ex(name, hash_size, tdb_flags,
346                           open_flags, mode, &log_ctx, NULL);
347         if (!tdb)
348                 return NULL;
349
350         return tdb;
351 }
352
353 /****************************************************************************
354  tdb_store, wrapped in a transaction. This way we make sure that a process
355  that dies within writing does not leave a corrupt tdb behind.
356 ****************************************************************************/
357
358 int tdb_trans_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
359                     int flag)
360 {
361         int res;
362
363         if ((res = tdb_transaction_start(tdb)) != 0) {
364                 DEBUG(5, ("tdb_transaction_start failed\n"));
365                 return res;
366         }
367
368         if ((res = tdb_store(tdb, key, dbuf, flag)) != 0) {
369                 DEBUG(10, ("tdb_store failed\n"));
370                 tdb_transaction_cancel(tdb);
371                 return res;
372         }
373
374         if ((res = tdb_transaction_commit(tdb)) != 0) {
375                 DEBUG(5, ("tdb_transaction_commit failed\n"));
376         }
377
378         return res;
379 }
380
381 /****************************************************************************
382  tdb_delete, wrapped in a transaction. This way we make sure that a process
383  that dies within deleting does not leave a corrupt tdb behind.
384 ****************************************************************************/
385
386 int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key)
387 {
388         int res;
389
390         if ((res = tdb_transaction_start(tdb)) != 0) {
391                 DEBUG(5, ("tdb_transaction_start failed\n"));
392                 return res;
393         }
394
395         if ((res = tdb_delete(tdb, key)) != 0) {
396                 DEBUG(10, ("tdb_delete failed\n"));
397                 tdb_transaction_cancel(tdb);
398                 return res;
399         }
400
401         if ((res = tdb_transaction_commit(tdb)) != 0) {
402                 DEBUG(5, ("tdb_transaction_commit failed\n"));
403         }
404
405         return res;
406 }
407
408 int tdb_data_cmp(TDB_DATA t1, TDB_DATA t2)
409 {
410         int ret;
411         if (t1.dptr == NULL && t2.dptr != NULL) {
412                 return -1;
413         }
414         if (t1.dptr != NULL && t2.dptr == NULL) {
415                 return 1;
416         }
417         if (t1.dptr == t2.dptr) {
418                 return t1.dsize - t2.dsize;
419         }
420         ret = memcmp(t1.dptr, t2.dptr, MIN(t1.dsize, t2.dsize));
421         if (ret == 0) {
422                 return t1.dsize - t2.dsize;
423         }
424         return ret;
425 }
426
427 char *tdb_data_string(TALLOC_CTX *mem_ctx, TDB_DATA d)
428 {
429         int len;
430         char *ret = NULL;
431         cbuf *ost = cbuf_new(mem_ctx);
432
433         if (ost == NULL) {
434                 return NULL;
435         }
436
437         len = cbuf_printf(ost, "%zu:", d.dsize);
438         if (len == -1) {
439                 goto done;
440         }
441
442         if (d.dptr == NULL) {
443                 len = cbuf_puts(ost, "<NULL>", -1);
444         } else {
445                 len = cbuf_print_quoted(ost, (const char*)d.dptr, d.dsize);
446         }
447         if (len == -1) {
448                 goto done;
449         }
450
451         cbuf_swapptr(ost, &ret, 0);
452         talloc_steal(mem_ctx, ret);
453
454 done:
455         talloc_free(ost);
456         return ret;
457 }
458
459 static sig_atomic_t gotalarm;
460
461 /***************************************************************
462  Signal function to tell us we timed out.
463 ****************************************************************/
464
465 static void gotalarm_sig(int signum)
466 {
467         gotalarm = 1;
468 }
469
470 /****************************************************************************
471  Lock a chain with timeout (in seconds).
472 ****************************************************************************/
473
474 static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type)
475 {
476         /* Allow tdb_chainlock to be interrupted by an alarm. */
477         int ret;
478         gotalarm = 0;
479
480         if (timeout) {
481                 CatchSignal(SIGALRM, gotalarm_sig);
482                 tdb_setalarm_sigptr(tdb, &gotalarm);
483                 alarm(timeout);
484         }
485
486         if (rw_type == F_RDLCK)
487                 ret = tdb_chainlock_read(tdb, key);
488         else
489                 ret = tdb_chainlock(tdb, key);
490
491         if (timeout) {
492                 alarm(0);
493                 tdb_setalarm_sigptr(tdb, NULL);
494                 CatchSignal(SIGALRM, SIG_IGN);
495                 if (gotalarm && (ret != 0)) {
496                         DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
497                                 timeout, key.dptr, tdb_name(tdb)));
498                         /* TODO: If we time out waiting for a lock, it might
499                          * be nice to use F_GETLK to get the pid of the
500                          * process currently holding the lock and print that
501                          * as part of the debugging message. -- mbp */
502                         return -1;
503                 }
504         }
505
506         return ret == 0 ? 0 : -1;
507 }
508
509 /****************************************************************************
510  Write lock a chain. Return non-zero if timeout or lock failed.
511 ****************************************************************************/
512
513 int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
514 {
515         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
516 }
517
518 int tdb_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
519                                    int timeout)
520 {
521         TDB_DATA key = string_term_tdb_data(keyval);
522
523         return tdb_chainlock_with_timeout(tdb, key, timeout);
524 }
525
526 /****************************************************************************
527  Read lock a chain by string. Return non-zero if timeout or lock failed.
528 ****************************************************************************/
529
530 int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
531 {
532         TDB_DATA key = string_term_tdb_data(keyval);
533
534         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
535 }