s3-includes: only include system/filesys.h when needed.
[kai/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 #undef malloc
25 #undef realloc
26 #undef calloc
27 #undef strdup
28
29 /* these are little tdb utility functions that are meant to make
30    dealing with a tdb database a little less cumbersome in Samba */
31
32 static SIG_ATOMIC_T gotalarm;
33
34 /***************************************************************
35  Signal function to tell us we timed out.
36 ****************************************************************/
37
38 static void gotalarm_sig(int signum)
39 {
40         gotalarm = 1;
41 }
42
43 /****************************************************************************
44  Lock a chain with timeout (in seconds).
45 ****************************************************************************/
46
47 static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type)
48 {
49         /* Allow tdb_chainlock to be interrupted by an alarm. */
50         int ret;
51         gotalarm = 0;
52
53         if (timeout) {
54                 CatchSignal(SIGALRM, gotalarm_sig);
55                 tdb_setalarm_sigptr(tdb, &gotalarm);
56                 alarm(timeout);
57         }
58
59         if (rw_type == F_RDLCK)
60                 ret = tdb_chainlock_read(tdb, key);
61         else
62                 ret = tdb_chainlock(tdb, key);
63
64         if (timeout) {
65                 alarm(0);
66                 tdb_setalarm_sigptr(tdb, NULL);
67                 CatchSignal(SIGALRM, SIG_IGN);
68                 if (gotalarm && (ret == -1)) {
69                         DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
70                                 timeout, key.dptr, tdb_name(tdb)));
71                         /* TODO: If we time out waiting for a lock, it might
72                          * be nice to use F_GETLK to get the pid of the
73                          * process currently holding the lock and print that
74                          * as part of the debugging message. -- mbp */
75                         return -1;
76                 }
77         }
78
79         return ret;
80 }
81
82 /****************************************************************************
83  Write lock a chain. Return -1 if timeout or lock failed.
84 ****************************************************************************/
85
86 int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
87 {
88         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
89 }
90
91 int tdb_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
92                                    int timeout)
93 {
94         TDB_DATA key = string_term_tdb_data(keyval);
95
96         return tdb_chainlock_with_timeout(tdb, key, timeout);
97 }
98
99 /****************************************************************************
100  Read lock a chain by string. Return -1 if timeout or lock failed.
101 ****************************************************************************/
102
103 int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
104 {
105         TDB_DATA key = string_term_tdb_data(keyval);
106
107         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
108 }
109
110
111
112
113 int tdb_trans_store_bystring(TDB_CONTEXT *tdb, const char *keystr,
114                              TDB_DATA data, int flags)
115 {
116         TDB_DATA key = string_term_tdb_data(keystr);
117
118         return tdb_trans_store(tdb, key, data, flags);
119 }
120
121 /****************************************************************************
122  Useful pair of routines for packing/unpacking data consisting of
123  integers and strings.
124 ****************************************************************************/
125
126 static size_t tdb_pack_va(uint8 *buf, int bufsize, const char *fmt, va_list ap)
127 {
128         uint8 bt;
129         uint16 w;
130         uint32 d;
131         int i;
132         void *p;
133         int len;
134         char *s;
135         char c;
136         uint8 *buf0 = buf;
137         const char *fmt0 = fmt;
138         int bufsize0 = bufsize;
139
140         while (*fmt) {
141                 switch ((c = *fmt++)) {
142                 case 'b': /* unsigned 8-bit integer */
143                         len = 1;
144                         bt = (uint8)va_arg(ap, int);
145                         if (bufsize && bufsize >= len)
146                                 SSVAL(buf, 0, bt);
147                         break;
148                 case 'w': /* unsigned 16-bit integer */
149                         len = 2;
150                         w = (uint16)va_arg(ap, int);
151                         if (bufsize && bufsize >= len)
152                                 SSVAL(buf, 0, w);
153                         break;
154                 case 'd': /* signed 32-bit integer (standard int in most systems) */
155                         len = 4;
156                         d = va_arg(ap, uint32);
157                         if (bufsize && bufsize >= len)
158                                 SIVAL(buf, 0, d);
159                         break;
160                 case 'p': /* pointer */
161                         len = 4;
162                         p = va_arg(ap, void *);
163                         d = p?1:0;
164                         if (bufsize && bufsize >= len)
165                                 SIVAL(buf, 0, d);
166                         break;
167                 case 'P': /* null-terminated string */
168                         s = va_arg(ap,char *);
169                         w = strlen(s);
170                         len = w + 1;
171                         if (bufsize && bufsize >= len)
172                                 memcpy(buf, s, len);
173                         break;
174                 case 'f': /* null-terminated string */
175                         s = va_arg(ap,char *);
176                         w = strlen(s);
177                         len = w + 1;
178                         if (bufsize && bufsize >= len)
179                                 memcpy(buf, s, len);
180                         break;
181                 case 'B': /* fixed-length string */
182                         i = va_arg(ap, int);
183                         s = va_arg(ap, char *);
184                         len = 4+i;
185                         if (bufsize && bufsize >= len) {
186                                 SIVAL(buf, 0, i);
187                                 memcpy(buf+4, s, i);
188                         }
189                         break;
190                 default:
191                         DEBUG(0,("Unknown tdb_pack format %c in %s\n", 
192                                  c, fmt));
193                         len = 0;
194                         break;
195                 }
196
197                 buf += len;
198                 if (bufsize)
199                         bufsize -= len;
200                 if (bufsize < 0)
201                         bufsize = 0;
202         }
203
204         DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n", 
205                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
206
207         return PTR_DIFF(buf, buf0);
208 }
209
210 size_t tdb_pack(uint8 *buf, int bufsize, const char *fmt, ...)
211 {
212         va_list ap;
213         size_t result;
214
215         va_start(ap, fmt);
216         result = tdb_pack_va(buf, bufsize, fmt, ap);
217         va_end(ap);
218         return result;
219 }
220
221 bool tdb_pack_append(TALLOC_CTX *mem_ctx, uint8 **buf, size_t *len,
222                      const char *fmt, ...)
223 {
224         va_list ap;
225         size_t len1, len2;
226
227         va_start(ap, fmt);
228         len1 = tdb_pack_va(NULL, 0, fmt, ap);
229         va_end(ap);
230
231         if (mem_ctx != NULL) {
232                 *buf = TALLOC_REALLOC_ARRAY(mem_ctx, *buf, uint8,
233                                             (*len) + len1);
234         } else {
235                 *buf = SMB_REALLOC_ARRAY(*buf, uint8, (*len) + len1);
236         }
237
238         if (*buf == NULL) {
239                 return False;
240         }
241
242         va_start(ap, fmt);
243         len2 = tdb_pack_va((*buf)+(*len), len1, fmt, ap);
244         va_end(ap);
245
246         if (len1 != len2) {
247                 return False;
248         }
249
250         *len += len2;
251
252         return True;
253 }
254
255 /****************************************************************************
256  Useful pair of routines for packing/unpacking data consisting of
257  integers and strings.
258 ****************************************************************************/
259
260 int tdb_unpack(const uint8 *buf, int bufsize, const char *fmt, ...)
261 {
262         va_list ap;
263         uint8 *bt;
264         uint16 *w;
265         uint32 *d;
266         int len;
267         int *i;
268         void **p;
269         char *s, **b, **ps;
270         char c;
271         const uint8 *buf0 = buf;
272         const char *fmt0 = fmt;
273         int bufsize0 = bufsize;
274
275         va_start(ap, fmt);
276
277         while (*fmt) {
278                 switch ((c=*fmt++)) {
279                 case 'b': /* unsigned 8-bit integer */
280                         len = 1;
281                         bt = va_arg(ap, uint8 *);
282                         if (bufsize < len)
283                                 goto no_space;
284                         *bt = SVAL(buf, 0);
285                         break;
286                 case 'w': /* unsigned 16-bit integer */
287                         len = 2;
288                         w = va_arg(ap, uint16 *);
289                         if (bufsize < len)
290                                 goto no_space;
291                         *w = SVAL(buf, 0);
292                         break;
293                 case 'd': /* signed 32-bit integer (standard int in most systems) */
294                         len = 4;
295                         d = va_arg(ap, uint32 *);
296                         if (bufsize < len)
297                                 goto no_space;
298                         *d = IVAL(buf, 0);
299                         break;
300                 case 'p': /* pointer */
301                         len = 4;
302                         p = va_arg(ap, void **);
303                         if (bufsize < len)
304                                 goto no_space;
305                         /*
306                          * This isn't a real pointer - only a token (1 or 0)
307                          * to mark the fact a pointer is present.
308                          */
309
310                         *p = (void *)(IVAL(buf, 0) ? (void *)1 : NULL);
311                         break;
312                 case 'P': /* null-terminated string */
313                         /* Return malloc'ed string. */
314                         ps = va_arg(ap,char **);
315                         len = strlen((const char *)buf) + 1;
316                         *ps = SMB_STRDUP((const char *)buf);
317                         break;
318                 case 'f': /* null-terminated string */
319                         s = va_arg(ap,char *);
320                         len = strlen((const char *)buf) + 1;
321                         if (bufsize < len || len > sizeof(fstring))
322                                 goto no_space;
323                         memcpy(s, buf, len);
324                         break;
325                 case 'B': /* fixed-length string */
326                         i = va_arg(ap, int *);
327                         b = va_arg(ap, char **);
328                         len = 4;
329                         if (bufsize < len)
330                                 goto no_space;
331                         *i = IVAL(buf, 0);
332                         if (! *i) {
333                                 *b = NULL;
334                                 break;
335                         }
336                         len += *i;
337                         if (bufsize < len)
338                                 goto no_space;
339                         *b = (char *)SMB_MALLOC(*i);
340                         if (! *b)
341                                 goto no_space;
342                         memcpy(*b, buf+4, *i);
343                         break;
344                 default:
345                         DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
346                                  c, fmt));
347
348                         len = 0;
349                         break;
350                 }
351
352                 buf += len;
353                 bufsize -= len;
354         }
355
356         va_end(ap);
357
358         DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
359                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
360
361         return PTR_DIFF(buf, buf0);
362
363  no_space:
364         va_end(ap);
365         return -1;
366 }
367
368
369 /****************************************************************************
370  Log tdb messages via DEBUG().
371 ****************************************************************************/
372
373 static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
374 {
375         va_list ap;
376         char *ptr = NULL;
377         int ret;
378
379         va_start(ap, format);
380         ret = vasprintf(&ptr, format, ap);
381         va_end(ap);
382
383         if ((ret == -1) || !*ptr)
384                 return;
385
386         DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
387         SAFE_FREE(ptr);
388 }
389
390 /****************************************************************************
391  Like tdb_open() but also setup a logging function that redirects to
392  the samba DEBUG() system.
393 ****************************************************************************/
394
395 TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
396                           int open_flags, mode_t mode)
397 {
398         TDB_CONTEXT *tdb;
399         struct tdb_logging_context log_ctx;
400
401         if (!lp_use_mmap())
402                 tdb_flags |= TDB_NOMMAP;
403
404         log_ctx.log_fn = tdb_log;
405         log_ctx.log_private = NULL;
406
407         if ((hash_size == 0) && (name != NULL)) {
408                 const char *base = strrchr_m(name, '/');
409                 if (base != NULL) {
410                         base += 1;
411                 }
412                 else {
413                         base = name;
414                 }
415                 hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
416         }
417
418         tdb = tdb_open_ex(name, hash_size, tdb_flags, 
419                           open_flags, mode, &log_ctx, NULL);
420         if (!tdb)
421                 return NULL;
422
423         return tdb;
424 }
425
426 /****************************************************************************
427  tdb_store, wrapped in a transaction. This way we make sure that a process
428  that dies within writing does not leave a corrupt tdb behind.
429 ****************************************************************************/
430
431 int tdb_trans_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
432                     int flag)
433 {
434         int res;
435
436         if ((res = tdb_transaction_start(tdb)) != 0) {
437                 DEBUG(5, ("tdb_transaction_start failed\n"));
438                 return res;
439         }
440
441         if ((res = tdb_store(tdb, key, dbuf, flag)) != 0) {
442                 DEBUG(10, ("tdb_store failed\n"));
443                 if (tdb_transaction_cancel(tdb) != 0) {
444                         smb_panic("Cancelling transaction failed");
445                 }
446                 return res;
447         }
448
449         if ((res = tdb_transaction_commit(tdb)) != 0) {
450                 DEBUG(5, ("tdb_transaction_commit failed\n"));
451         }
452
453         return res;
454 }
455
456 /****************************************************************************
457  tdb_delete, wrapped in a transaction. This way we make sure that a process
458  that dies within deleting does not leave a corrupt tdb behind.
459 ****************************************************************************/
460
461 int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key)
462 {
463         int res;
464
465         if ((res = tdb_transaction_start(tdb)) != 0) {
466                 DEBUG(5, ("tdb_transaction_start failed\n"));
467                 return res;
468         }
469
470         if ((res = tdb_delete(tdb, key)) != 0) {
471                 DEBUG(10, ("tdb_delete failed\n"));
472                 if (tdb_transaction_cancel(tdb) != 0) {
473                         smb_panic("Cancelling transaction failed");
474                 }
475                 return res;
476         }
477
478         if ((res = tdb_transaction_commit(tdb)) != 0) {
479                 DEBUG(5, ("tdb_transaction_commit failed\n"));
480         }
481
482         return res;
483 }
484
485 /*
486  Log tdb messages via DEBUG().
487 */
488 static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, 
489                          const char *format, ...) PRINTF_ATTRIBUTE(3,4);
490
491 static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, 
492                          const char *format, ...)
493 {
494         va_list ap;
495         char *ptr = NULL;
496         int debuglevel = 0;
497         int ret;
498
499         switch (level) {
500         case TDB_DEBUG_FATAL:
501                 debuglevel = 0;
502                 break;
503         case TDB_DEBUG_ERROR:
504                 debuglevel = 1;
505                 break;
506         case TDB_DEBUG_WARNING:
507                 debuglevel = 2;
508                 break;
509         case TDB_DEBUG_TRACE:
510                 debuglevel = 5;
511                 break;
512         default:
513                 debuglevel = 0;
514         }               
515
516         va_start(ap, format);
517         ret = vasprintf(&ptr, format, ap);
518         va_end(ap);
519
520         if (ret != -1) {
521                 const char *name = tdb_name(tdb);
522                 DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr));
523                 free(ptr);
524         }
525 }
526
527 struct tdb_wrap_private {
528         struct tdb_context *tdb;
529         const char *name;
530         struct tdb_wrap_private *next, *prev;
531 };
532
533 static struct tdb_wrap_private *tdb_list;
534
535 /* destroy the last connection to a tdb */
536 static int tdb_wrap_private_destructor(struct tdb_wrap_private *w)
537 {
538         tdb_close(w->tdb);
539         DLIST_REMOVE(tdb_list, w);
540         return 0;
541 }                                
542
543 static struct tdb_wrap_private *tdb_wrap_private_open(TALLOC_CTX *mem_ctx,
544                                                       const char *name,
545                                                       int hash_size,
546                                                       int tdb_flags,
547                                                       int open_flags,
548                                                       mode_t mode)
549 {
550         struct tdb_wrap_private *result;
551         struct tdb_logging_context log_ctx;
552
553         result = talloc(mem_ctx, struct tdb_wrap_private);
554         if (result == NULL) {
555                 return NULL;
556         }
557         result->name = talloc_strdup(result, name);
558         if (result->name == NULL) {
559                 goto fail;
560         }
561
562         log_ctx.log_fn = tdb_wrap_log;
563
564         if (!lp_use_mmap()) {
565                 tdb_flags |= TDB_NOMMAP;
566         }
567
568         if ((hash_size == 0) && (name != NULL)) {
569                 const char *base;
570                 base = strrchr_m(name, '/');
571
572                 if (base != NULL) {
573                         base += 1;
574                 } else {
575                         base = name;
576                 }
577                 hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
578         }
579
580         result->tdb = tdb_open_ex(name, hash_size, tdb_flags,
581                                   open_flags, mode, &log_ctx, NULL);
582         if (result->tdb == NULL) {
583                 goto fail;
584         }
585         talloc_set_destructor(result, tdb_wrap_private_destructor);
586         DLIST_ADD(tdb_list, result);
587         return result;
588
589 fail:
590         TALLOC_FREE(result);
591         return NULL;
592 }
593
594 /*
595   wrapped connection to a tdb database
596   to close just talloc_free() the tdb_wrap pointer
597  */
598 struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
599                                const char *name, int hash_size, int tdb_flags,
600                                int open_flags, mode_t mode)
601 {
602         struct tdb_wrap *result;
603         struct tdb_wrap_private *w;
604
605         result = talloc(mem_ctx, struct tdb_wrap);
606         if (result == NULL) {
607                 return NULL;
608         }
609
610         for (w=tdb_list;w;w=w->next) {
611                 if (strcmp(name, w->name) == 0) {
612                         break;
613                 }
614         }
615
616         if (w == NULL) {
617                 w = tdb_wrap_private_open(result, name, hash_size, tdb_flags,
618                                           open_flags, mode);
619         } else {
620                 /*
621                  * Correctly use talloc_reference: The tdb will be
622                  * closed when "w" is being freed. The caller never
623                  * sees "w", so an incorrect use of talloc_free(w)
624                  * instead of calling talloc_unlink is not possible.
625                  * To avoid having to refcount ourselves, "w" will
626                  * have multiple parents that hang off all the
627                  * tdb_wrap's being returned from here. Those parents
628                  * can be freed without problem.
629                  */
630                 if (talloc_reference(result, w) == NULL) {
631                         goto fail;
632                 }
633         }
634         if (w == NULL) {
635                 goto fail;
636         }
637         result->tdb = w->tdb;
638         return result;
639 fail:
640         TALLOC_FREE(result);
641         return NULL;
642 }
643
644 NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err)
645 {
646         NTSTATUS result = NT_STATUS_INTERNAL_ERROR;
647
648         switch (err) {
649         case TDB_SUCCESS:
650                 result = NT_STATUS_OK;
651                 break;
652         case TDB_ERR_CORRUPT:
653                 result = NT_STATUS_INTERNAL_DB_CORRUPTION;
654                 break;
655         case TDB_ERR_IO:
656                 result = NT_STATUS_UNEXPECTED_IO_ERROR;
657                 break;
658         case TDB_ERR_OOM:
659                 result = NT_STATUS_NO_MEMORY;
660                 break;
661         case TDB_ERR_EXISTS:
662                 result = NT_STATUS_OBJECT_NAME_COLLISION;
663                 break;
664
665         case TDB_ERR_LOCK:
666                 /*
667                  * TDB_ERR_LOCK is very broad, we could for example
668                  * distinguish between fcntl locks and invalid lock
669                  * sequences. So NT_STATUS_FILE_LOCK_CONFLICT is a
670                  * compromise.
671                  */
672                 result = NT_STATUS_FILE_LOCK_CONFLICT;
673                 break;
674
675         case TDB_ERR_NOLOCK:
676         case TDB_ERR_LOCK_TIMEOUT:
677                 /*
678                  * These two ones in the enum are not actually used
679                  */
680                 result = NT_STATUS_FILE_LOCK_CONFLICT;
681                 break;
682         case TDB_ERR_NOEXIST:
683                 result = NT_STATUS_NOT_FOUND;
684                 break;
685         case TDB_ERR_EINVAL:
686                 result = NT_STATUS_INVALID_PARAMETER;
687                 break;
688         case TDB_ERR_RDONLY:
689                 result = NT_STATUS_ACCESS_DENIED;
690                 break;
691         case TDB_ERR_NESTING:
692                 result = NT_STATUS_INTERNAL_ERROR;
693                 break;
694         };
695         return result;
696 }
697
698 int tdb_data_cmp(TDB_DATA t1, TDB_DATA t2)
699 {
700         int ret;
701         if (t1.dptr == NULL && t2.dptr != NULL) {
702                 return -1;
703         }
704         if (t1.dptr != NULL && t2.dptr == NULL) {
705                 return 1;
706         }
707         if (t1.dptr == t2.dptr) {
708                 return t1.dsize - t2.dsize;
709         }
710         ret = memcmp(t1.dptr, t2.dptr, MIN(t1.dsize, t2.dsize));
711         if (ret == 0) {
712                 return t1.dsize - t2.dsize;
713         }
714         return ret;
715 }