libsmbconf: Convert smbconf_get_share_names() to sbcErr.
[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
26 #undef malloc
27 #undef realloc
28 #undef calloc
29 #undef strdup
30
31 /* these are little tdb utility functions that are meant to make
32    dealing with a tdb database a little less cumbersome in Samba */
33
34 static SIG_ATOMIC_T gotalarm;
35
36 /***************************************************************
37  Signal function to tell us we timed out.
38 ****************************************************************/
39
40 static void gotalarm_sig(int signum)
41 {
42         gotalarm = 1;
43 }
44
45 /****************************************************************************
46  Lock a chain with timeout (in seconds).
47 ****************************************************************************/
48
49 static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type)
50 {
51         /* Allow tdb_chainlock to be interrupted by an alarm. */
52         int ret;
53         gotalarm = 0;
54
55         if (timeout) {
56                 CatchSignal(SIGALRM, gotalarm_sig);
57                 tdb_setalarm_sigptr(tdb, &gotalarm);
58                 alarm(timeout);
59         }
60
61         if (rw_type == F_RDLCK)
62                 ret = tdb_chainlock_read(tdb, key);
63         else
64                 ret = tdb_chainlock(tdb, key);
65
66         if (timeout) {
67                 alarm(0);
68                 tdb_setalarm_sigptr(tdb, NULL);
69                 CatchSignal(SIGALRM, SIG_IGN);
70                 if (gotalarm && (ret == -1)) {
71                         DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
72                                 timeout, key.dptr, tdb_name(tdb)));
73                         /* TODO: If we time out waiting for a lock, it might
74                          * be nice to use F_GETLK to get the pid of the
75                          * process currently holding the lock and print that
76                          * as part of the debugging message. -- mbp */
77                         return -1;
78                 }
79         }
80
81         return ret;
82 }
83
84 /****************************************************************************
85  Write lock a chain. Return -1 if timeout or lock failed.
86 ****************************************************************************/
87
88 int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
89 {
90         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
91 }
92
93 int tdb_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
94                                    int timeout)
95 {
96         TDB_DATA key = string_term_tdb_data(keyval);
97
98         return tdb_chainlock_with_timeout(tdb, key, timeout);
99 }
100
101 /****************************************************************************
102  Read lock a chain by string. Return -1 if timeout or lock failed.
103 ****************************************************************************/
104
105 int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
106 {
107         TDB_DATA key = string_term_tdb_data(keyval);
108
109         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
110 }
111
112
113
114
115 int tdb_trans_store_bystring(TDB_CONTEXT *tdb, const char *keystr,
116                              TDB_DATA data, int flags)
117 {
118         TDB_DATA key = string_term_tdb_data(keystr);
119
120         return tdb_trans_store(tdb, key, data, flags);
121 }
122
123 /****************************************************************************
124  Useful pair of routines for packing/unpacking data consisting of
125  integers and strings.
126 ****************************************************************************/
127
128 static size_t tdb_pack_va(uint8 *buf, int bufsize, const char *fmt, va_list ap)
129 {
130         uint8 bt;
131         uint16 w;
132         uint32 d;
133         int i;
134         void *p;
135         int len;
136         char *s;
137         char c;
138         uint8 *buf0 = buf;
139         const char *fmt0 = fmt;
140         int bufsize0 = bufsize;
141
142         while (*fmt) {
143                 switch ((c = *fmt++)) {
144                 case 'b': /* unsigned 8-bit integer */
145                         len = 1;
146                         bt = (uint8)va_arg(ap, int);
147                         if (bufsize && bufsize >= len)
148                                 SSVAL(buf, 0, bt);
149                         break;
150                 case 'w': /* unsigned 16-bit integer */
151                         len = 2;
152                         w = (uint16)va_arg(ap, int);
153                         if (bufsize && bufsize >= len)
154                                 SSVAL(buf, 0, w);
155                         break;
156                 case 'd': /* signed 32-bit integer (standard int in most systems) */
157                         len = 4;
158                         d = va_arg(ap, uint32);
159                         if (bufsize && bufsize >= len)
160                                 SIVAL(buf, 0, d);
161                         break;
162                 case 'p': /* pointer */
163                         len = 4;
164                         p = va_arg(ap, void *);
165                         d = p?1:0;
166                         if (bufsize && bufsize >= len)
167                                 SIVAL(buf, 0, d);
168                         break;
169                 case 'P': /* null-terminated string */
170                         s = va_arg(ap,char *);
171                         w = strlen(s);
172                         len = w + 1;
173                         if (bufsize && bufsize >= len)
174                                 memcpy(buf, s, len);
175                         break;
176                 case 'f': /* null-terminated string */
177                         s = va_arg(ap,char *);
178                         w = strlen(s);
179                         len = w + 1;
180                         if (bufsize && bufsize >= len)
181                                 memcpy(buf, s, len);
182                         break;
183                 case 'B': /* fixed-length string */
184                         i = va_arg(ap, int);
185                         s = va_arg(ap, char *);
186                         len = 4+i;
187                         if (bufsize && bufsize >= len) {
188                                 SIVAL(buf, 0, i);
189                                 memcpy(buf+4, s, i);
190                         }
191                         break;
192                 default:
193                         DEBUG(0,("Unknown tdb_pack format %c in %s\n", 
194                                  c, fmt));
195                         len = 0;
196                         break;
197                 }
198
199                 buf += len;
200                 if (bufsize)
201                         bufsize -= len;
202                 if (bufsize < 0)
203                         bufsize = 0;
204         }
205
206         DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n", 
207                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
208
209         return PTR_DIFF(buf, buf0);
210 }
211
212 size_t tdb_pack(uint8 *buf, int bufsize, const char *fmt, ...)
213 {
214         va_list ap;
215         size_t result;
216
217         va_start(ap, fmt);
218         result = tdb_pack_va(buf, bufsize, fmt, ap);
219         va_end(ap);
220         return result;
221 }
222
223 bool tdb_pack_append(TALLOC_CTX *mem_ctx, uint8 **buf, size_t *len,
224                      const char *fmt, ...)
225 {
226         va_list ap;
227         size_t len1, len2;
228
229         va_start(ap, fmt);
230         len1 = tdb_pack_va(NULL, 0, fmt, ap);
231         va_end(ap);
232
233         if (mem_ctx != NULL) {
234                 *buf = TALLOC_REALLOC_ARRAY(mem_ctx, *buf, uint8,
235                                             (*len) + len1);
236         } else {
237                 *buf = SMB_REALLOC_ARRAY(*buf, uint8, (*len) + len1);
238         }
239
240         if (*buf == NULL) {
241                 return False;
242         }
243
244         va_start(ap, fmt);
245         len2 = tdb_pack_va((*buf)+(*len), len1, fmt, ap);
246         va_end(ap);
247
248         if (len1 != len2) {
249                 return False;
250         }
251
252         *len += len2;
253
254         return True;
255 }
256
257 /****************************************************************************
258  Useful pair of routines for packing/unpacking data consisting of
259  integers and strings.
260 ****************************************************************************/
261
262 int tdb_unpack(const uint8 *buf, int bufsize, const char *fmt, ...)
263 {
264         va_list ap;
265         uint8 *bt;
266         uint16 *w;
267         uint32 *d;
268         int len;
269         int *i;
270         void **p;
271         char *s, **b, **ps;
272         char c;
273         const uint8 *buf0 = buf;
274         const char *fmt0 = fmt;
275         int bufsize0 = bufsize;
276
277         va_start(ap, fmt);
278
279         while (*fmt) {
280                 switch ((c=*fmt++)) {
281                 case 'b': /* unsigned 8-bit integer */
282                         len = 1;
283                         bt = va_arg(ap, uint8 *);
284                         if (bufsize < len)
285                                 goto no_space;
286                         *bt = SVAL(buf, 0);
287                         break;
288                 case 'w': /* unsigned 16-bit integer */
289                         len = 2;
290                         w = va_arg(ap, uint16 *);
291                         if (bufsize < len)
292                                 goto no_space;
293                         *w = SVAL(buf, 0);
294                         break;
295                 case 'd': /* signed 32-bit integer (standard int in most systems) */
296                         len = 4;
297                         d = va_arg(ap, uint32 *);
298                         if (bufsize < len)
299                                 goto no_space;
300                         *d = IVAL(buf, 0);
301                         break;
302                 case 'p': /* pointer */
303                         len = 4;
304                         p = va_arg(ap, void **);
305                         if (bufsize < len)
306                                 goto no_space;
307                         /*
308                          * This isn't a real pointer - only a token (1 or 0)
309                          * to mark the fact a pointer is present.
310                          */
311
312                         *p = (void *)(IVAL(buf, 0) ? (void *)1 : NULL);
313                         break;
314                 case 'P': /* null-terminated string */
315                         /* Return malloc'ed string. */
316                         ps = va_arg(ap,char **);
317                         len = strlen((const char *)buf) + 1;
318                         *ps = SMB_STRDUP((const char *)buf);
319                         break;
320                 case 'f': /* null-terminated string */
321                         s = va_arg(ap,char *);
322                         len = strlen((const char *)buf) + 1;
323                         if (bufsize < len || len > sizeof(fstring))
324                                 goto no_space;
325                         memcpy(s, buf, len);
326                         break;
327                 case 'B': /* fixed-length string */
328                         i = va_arg(ap, int *);
329                         b = va_arg(ap, char **);
330                         len = 4;
331                         if (bufsize < len)
332                                 goto no_space;
333                         *i = IVAL(buf, 0);
334                         if (! *i) {
335                                 *b = NULL;
336                                 break;
337                         }
338                         len += *i;
339                         if (bufsize < len)
340                                 goto no_space;
341                         *b = (char *)SMB_MALLOC(*i);
342                         if (! *b)
343                                 goto no_space;
344                         memcpy(*b, buf+4, *i);
345                         break;
346                 default:
347                         DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
348                                  c, fmt));
349
350                         len = 0;
351                         break;
352                 }
353
354                 buf += len;
355                 bufsize -= len;
356         }
357
358         va_end(ap);
359
360         DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
361                  fmt0, bufsize0, (int)PTR_DIFF(buf, buf0)));
362
363         return PTR_DIFF(buf, buf0);
364
365  no_space:
366         va_end(ap);
367         return -1;
368 }
369
370
371 /****************************************************************************
372  Log tdb messages via DEBUG().
373 ****************************************************************************/
374
375 static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
376 {
377         va_list ap;
378         char *ptr = NULL;
379         int ret;
380
381         va_start(ap, format);
382         ret = vasprintf(&ptr, format, ap);
383         va_end(ap);
384
385         if ((ret == -1) || !*ptr)
386                 return;
387
388         DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
389         SAFE_FREE(ptr);
390 }
391
392 /****************************************************************************
393  Like tdb_open() but also setup a logging function that redirects to
394  the samba DEBUG() system.
395 ****************************************************************************/
396
397 TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
398                           int open_flags, mode_t mode)
399 {
400         TDB_CONTEXT *tdb;
401         struct tdb_logging_context log_ctx;
402
403         if (!lp_use_mmap())
404                 tdb_flags |= TDB_NOMMAP;
405
406         log_ctx.log_fn = tdb_log;
407         log_ctx.log_private = NULL;
408
409         if ((hash_size == 0) && (name != NULL)) {
410                 const char *base = strrchr_m(name, '/');
411                 if (base != NULL) {
412                         base += 1;
413                 }
414                 else {
415                         base = name;
416                 }
417                 hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
418         }
419
420         tdb = tdb_open_ex(name, hash_size, tdb_flags, 
421                           open_flags, mode, &log_ctx, NULL);
422         if (!tdb)
423                 return NULL;
424
425         return tdb;
426 }
427
428 /****************************************************************************
429  tdb_store, wrapped in a transaction. This way we make sure that a process
430  that dies within writing does not leave a corrupt tdb behind.
431 ****************************************************************************/
432
433 int tdb_trans_store(struct tdb_context *tdb, TDB_DATA key, TDB_DATA dbuf,
434                     int flag)
435 {
436         int res;
437
438         if ((res = tdb_transaction_start(tdb)) != 0) {
439                 DEBUG(5, ("tdb_transaction_start failed\n"));
440                 return res;
441         }
442
443         if ((res = tdb_store(tdb, key, dbuf, flag)) != 0) {
444                 DEBUG(10, ("tdb_store failed\n"));
445                 if (tdb_transaction_cancel(tdb) != 0) {
446                         smb_panic("Cancelling transaction failed");
447                 }
448                 return res;
449         }
450
451         if ((res = tdb_transaction_commit(tdb)) != 0) {
452                 DEBUG(5, ("tdb_transaction_commit failed\n"));
453         }
454
455         return res;
456 }
457
458 /****************************************************************************
459  tdb_delete, wrapped in a transaction. This way we make sure that a process
460  that dies within deleting does not leave a corrupt tdb behind.
461 ****************************************************************************/
462
463 int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key)
464 {
465         int res;
466
467         if ((res = tdb_transaction_start(tdb)) != 0) {
468                 DEBUG(5, ("tdb_transaction_start failed\n"));
469                 return res;
470         }
471
472         if ((res = tdb_delete(tdb, key)) != 0) {
473                 DEBUG(10, ("tdb_delete failed\n"));
474                 if (tdb_transaction_cancel(tdb) != 0) {
475                         smb_panic("Cancelling transaction failed");
476                 }
477                 return res;
478         }
479
480         if ((res = tdb_transaction_commit(tdb)) != 0) {
481                 DEBUG(5, ("tdb_transaction_commit failed\n"));
482         }
483
484         return res;
485 }
486
487 NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err)
488 {
489         NTSTATUS result = NT_STATUS_INTERNAL_ERROR;
490
491         switch (err) {
492         case TDB_SUCCESS:
493                 result = NT_STATUS_OK;
494                 break;
495         case TDB_ERR_CORRUPT:
496                 result = NT_STATUS_INTERNAL_DB_CORRUPTION;
497                 break;
498         case TDB_ERR_IO:
499                 result = NT_STATUS_UNEXPECTED_IO_ERROR;
500                 break;
501         case TDB_ERR_OOM:
502                 result = NT_STATUS_NO_MEMORY;
503                 break;
504         case TDB_ERR_EXISTS:
505                 result = NT_STATUS_OBJECT_NAME_COLLISION;
506                 break;
507
508         case TDB_ERR_LOCK:
509                 /*
510                  * TDB_ERR_LOCK is very broad, we could for example
511                  * distinguish between fcntl locks and invalid lock
512                  * sequences. So NT_STATUS_FILE_LOCK_CONFLICT is a
513                  * compromise.
514                  */
515                 result = NT_STATUS_FILE_LOCK_CONFLICT;
516                 break;
517
518         case TDB_ERR_NOLOCK:
519         case TDB_ERR_LOCK_TIMEOUT:
520                 /*
521                  * These two ones in the enum are not actually used
522                  */
523                 result = NT_STATUS_FILE_LOCK_CONFLICT;
524                 break;
525         case TDB_ERR_NOEXIST:
526                 result = NT_STATUS_NOT_FOUND;
527                 break;
528         case TDB_ERR_EINVAL:
529                 result = NT_STATUS_INVALID_PARAMETER;
530                 break;
531         case TDB_ERR_RDONLY:
532                 result = NT_STATUS_ACCESS_DENIED;
533                 break;
534         case TDB_ERR_NESTING:
535                 result = NT_STATUS_INTERNAL_ERROR;
536                 break;
537         };
538         return result;
539 }
540
541 int tdb_data_cmp(TDB_DATA t1, TDB_DATA t2)
542 {
543         int ret;
544         if (t1.dptr == NULL && t2.dptr != NULL) {
545                 return -1;
546         }
547         if (t1.dptr != NULL && t2.dptr == NULL) {
548                 return 1;
549         }
550         if (t1.dptr == t2.dptr) {
551                 return t1.dsize - t2.dsize;
552         }
553         ret = memcmp(t1.dptr, t2.dptr, MIN(t1.dsize, t2.dsize));
554         if (ret == 0) {
555                 return t1.dsize - t2.dsize;
556         }
557         return ret;
558 }