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