tdb_compat: use tdb_open_compat.
[kai/samba.git] / lib / util / tdb_wrap.c
1 /* 
2    Unix SMB/CIFS implementation.
3    TDB wrap functions
4
5    Copyright (C) Andrew Tridgell 2004
6    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 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 "lib/util/dlinklist.h"
24 #include "lib/util/tdb_wrap.h"
25
26 /* FIXME: TDB2 does this internally, so no need to wrap multiple opens! */
27 #if BUILD_TDB2
28 static void tdb_wrap_log(struct tdb_context *tdb,
29                          enum tdb_log_level level,
30                          const char *message,
31                          void *unused)
32 {
33         int dl;
34         const char *name = tdb_name(tdb);
35
36         switch (level) {
37         case TDB_LOG_USE_ERROR:
38         case TDB_LOG_ERROR:
39                 dl = 0;
40                 break;
41         case TDB_LOG_WARNING:
42                 dl = 2;
43                 break;
44         default:
45                 dl = 0;
46         }
47
48         DEBUG(dl, ("tdb(%s): %s", name ? name : "unnamed", message));
49 }
50 #else
51 /*
52  Log tdb messages via DEBUG().
53 */
54 static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, 
55                          const char *format, ...) PRINTF_ATTRIBUTE(3,4);
56
57 static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, 
58                          const char *format, ...)
59 {
60         va_list ap;
61         char *ptr = NULL;
62         int debuglevel = 0;
63         int ret;
64
65         switch (level) {
66         case TDB_DEBUG_FATAL:
67                 debuglevel = 0;
68                 break;
69         case TDB_DEBUG_ERROR:
70                 debuglevel = 1;
71                 break;
72         case TDB_DEBUG_WARNING:
73                 debuglevel = 2;
74                 break;
75         case TDB_DEBUG_TRACE:
76                 debuglevel = 5;
77                 break;
78         default:
79                 debuglevel = 0;
80         }               
81
82         va_start(ap, format);
83         ret = vasprintf(&ptr, format, ap);
84         va_end(ap);
85
86         if (ret != -1) {
87                 const char *name = tdb_name(tdb);
88                 DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr));
89                 free(ptr);
90         }
91 }
92 #endif
93
94 struct tdb_wrap_private {
95         struct tdb_context *tdb;
96         const char *name;
97         struct tdb_wrap_private *next, *prev;
98 };
99
100 static struct tdb_wrap_private *tdb_list;
101
102 /* destroy the last connection to a tdb */
103 static int tdb_wrap_private_destructor(struct tdb_wrap_private *w)
104 {
105         tdb_close(w->tdb);
106         DLIST_REMOVE(tdb_list, w);
107         return 0;
108 }                                
109
110 static struct tdb_wrap_private *tdb_wrap_private_open(TALLOC_CTX *mem_ctx,
111                                                       const char *name,
112                                                       int hash_size,
113                                                       int tdb_flags,
114                                                       int open_flags,
115                                                       mode_t mode)
116 {
117         struct tdb_wrap_private *result;
118
119         result = talloc(mem_ctx, struct tdb_wrap_private);
120         if (result == NULL) {
121                 return NULL;
122         }
123         result->name = talloc_strdup(result, name);
124         if (result->name == NULL) {
125                 goto fail;
126         }
127
128 #if _SAMBA_BUILD_ == 3  
129         /* This #if _SAMBA_BUILD == 3 is very unfortunate, as it means
130          * that in the top level build, these options are not
131          * available for these databases.  However, having two
132          * different tdb_wrap lists is a worse fate, so this will do
133          * for now */
134
135         if (!lp_use_mmap()) {
136                 tdb_flags |= TDB_NOMMAP;
137         }
138
139         if ((hash_size == 0) && (name != NULL)) {
140                 const char *base;
141                 base = strrchr_m(name, '/');
142
143                 if (base != NULL) {
144                         base += 1;
145                 } else {
146                         base = name;
147                 }
148                 hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
149         }
150 #endif
151
152         result->tdb = tdb_open_compat(name, hash_size, tdb_flags,
153                                       open_flags, mode, tdb_wrap_log, NULL);
154         if (result->tdb == NULL) {
155                 goto fail;
156         }
157         talloc_set_destructor(result, tdb_wrap_private_destructor);
158         DLIST_ADD(tdb_list, result);
159         return result;
160
161 fail:
162         TALLOC_FREE(result);
163         return NULL;
164 }
165
166 /*
167   wrapped connection to a tdb database
168   to close just talloc_free() the tdb_wrap pointer
169  */
170 struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx,
171                                const char *name, int hash_size, int tdb_flags,
172                                int open_flags, mode_t mode)
173 {
174         struct tdb_wrap *result;
175         struct tdb_wrap_private *w;
176
177         result = talloc(mem_ctx, struct tdb_wrap);
178         if (result == NULL) {
179                 return NULL;
180         }
181
182         for (w=tdb_list;w;w=w->next) {
183                 if (strcmp(name, w->name) == 0) {
184                         break;
185                 }
186         }
187
188         if (w == NULL) {
189                 w = tdb_wrap_private_open(result, name, hash_size, tdb_flags,
190                                           open_flags, mode);
191         } else {
192                 /*
193                  * Correctly use talloc_reference: The tdb will be
194                  * closed when "w" is being freed. The caller never
195                  * sees "w", so an incorrect use of talloc_free(w)
196                  * instead of calling talloc_unlink is not possible.
197                  * To avoid having to refcount ourselves, "w" will
198                  * have multiple parents that hang off all the
199                  * tdb_wrap's being returned from here. Those parents
200                  * can be freed without problem.
201                  */
202                 if (talloc_reference(result, w) == NULL) {
203                         goto fail;
204                 }
205         }
206         if (w == NULL) {
207                 goto fail;
208         }
209         result->tdb = w->tdb;
210         return result;
211 fail:
212         TALLOC_FREE(result);
213         return NULL;
214 }
215