4330c961ec55233a091d5a655a371689f3e7730f
[samba.git] / source3 / lib / dbwrap / dbwrap_tdb.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Database interface wrapper around tdb
4    Copyright (C) Volker Lendecke 2005-2007
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "dbwrap/dbwrap.h"
22 #include "dbwrap/dbwrap_private.h"
23 #include "dbwrap/dbwrap_tdb.h"
24 #include "lib/util/tdb_wrap.h"
25
26 struct db_tdb_ctx {
27         struct tdb_wrap *wtdb;
28 };
29
30 static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag);
31 static NTSTATUS db_tdb_delete(struct db_record *rec);
32
33 static int db_tdb_record_destr(struct db_record* data)
34 {
35         struct db_tdb_ctx *ctx =
36                 talloc_get_type_abort(data->private_data, struct db_tdb_ctx);
37
38         /* This hex_encode_talloc() call allocates memory on data context. By way how current 
39            __talloc_free() code works, it is OK to allocate in the destructor as 
40            the children of data will be freed after call to the destructor and this 
41            new 'child' will be caught and freed correctly.
42          */
43         DEBUG(10, (DEBUGLEVEL > 10
44                    ? "Unlocking key %s\n" : "Unlocking key %.20s\n",
45                    hex_encode_talloc(data, (unsigned char *)data->key.dptr,
46                               data->key.dsize)));
47
48         tdb_chainunlock(ctx->wtdb->tdb, data->key);
49         return 0;
50 }
51
52 struct tdb_fetch_locked_state {
53         TALLOC_CTX *mem_ctx;
54         struct db_record *result;
55 };
56
57 static int db_tdb_fetchlock_parse(TDB_DATA key, TDB_DATA data,
58                                   void *private_data)
59 {
60         struct tdb_fetch_locked_state *state =
61                 (struct tdb_fetch_locked_state *)private_data;
62
63         state->result = (struct db_record *)talloc_size(
64                 state->mem_ctx,
65                 sizeof(struct db_record) + key.dsize + data.dsize);
66
67         if (state->result == NULL) {
68                 return 0;
69         }
70
71         state->result->key.dsize = key.dsize;
72         state->result->key.dptr = ((uint8 *)state->result)
73                 + sizeof(struct db_record);
74         memcpy(state->result->key.dptr, key.dptr, key.dsize);
75
76         state->result->value.dsize = data.dsize;
77
78         if (data.dsize > 0) {
79                 state->result->value.dptr = state->result->key.dptr+key.dsize;
80                 memcpy(state->result->value.dptr, data.dptr, data.dsize);
81         }
82         else {
83                 state->result->value.dptr = NULL;
84         }
85
86         return 0;
87 }
88
89 static struct db_record *db_tdb_fetch_locked(struct db_context *db,
90                                      TALLOC_CTX *mem_ctx, TDB_DATA key)
91 {
92         struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
93                                                        struct db_tdb_ctx);
94         struct tdb_fetch_locked_state state;
95
96         /* Do not accidently allocate/deallocate w/o need when debug level is lower than needed */
97         if(DEBUGLEVEL >= 10) {
98                 char *keystr = hex_encode_talloc(talloc_tos(), (unsigned char*)key.dptr, key.dsize);
99                 DEBUG(10, (DEBUGLEVEL > 10
100                            ? "Locking key %s\n" : "Locking key %.20s\n",
101                            keystr));
102                 TALLOC_FREE(keystr);
103         }
104
105         if (tdb_chainlock(ctx->wtdb->tdb, key) != 0) {
106                 DEBUG(3, ("tdb_chainlock failed\n"));
107                 return NULL;
108         }
109
110         state.mem_ctx = mem_ctx;
111         state.result = NULL;
112
113         tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_fetchlock_parse, &state);
114
115         if (state.result == NULL) {
116                 db_tdb_fetchlock_parse(key, tdb_null, &state);
117         }
118
119         if (state.result == NULL) {
120                 tdb_chainunlock(ctx->wtdb->tdb, key);
121                 return NULL;
122         }
123
124         talloc_set_destructor(state.result, db_tdb_record_destr);
125
126         state.result->private_data = talloc_reference(state.result, ctx);
127         state.result->store = db_tdb_store;
128         state.result->delete_rec = db_tdb_delete;
129
130         DEBUG(10, ("Allocated locked data 0x%p\n", state.result));
131
132         return state.result;
133 }
134
135 struct tdb_fetch_state {
136         TALLOC_CTX *mem_ctx;
137         int result;
138         TDB_DATA data;
139 };
140
141 static int db_tdb_fetch_parse(TDB_DATA key, TDB_DATA data,
142                               void *private_data)
143 {
144         struct tdb_fetch_state *state =
145                 (struct tdb_fetch_state *)private_data;
146
147         state->data.dptr = (uint8 *)talloc_memdup(state->mem_ctx, data.dptr,
148                                                   data.dsize);
149         if (state->data.dptr == NULL) {
150                 state->result = -1;
151                 return 0;
152         }
153
154         state->data.dsize = data.dsize;
155         return 0;
156 }
157
158 static int db_tdb_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
159                         TDB_DATA key, TDB_DATA *pdata)
160 {
161         struct db_tdb_ctx *ctx = talloc_get_type_abort(
162                 db->private_data, struct db_tdb_ctx);
163
164         struct tdb_fetch_state state;
165         int ret;
166
167         state.mem_ctx = mem_ctx;
168         state.result = 0;
169         state.data = tdb_null;
170
171         ret = tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_fetch_parse, &state);
172
173         if (ret != 0) {
174                 return -1;
175         }
176
177         if (state.result == -1) {
178                 return -1;
179         }
180
181         *pdata = state.data;
182         return 0;
183 }
184
185 static int db_tdb_exists(struct db_context *db, TDB_DATA key)
186 {
187         struct db_tdb_ctx *ctx = talloc_get_type_abort(
188                 db->private_data, struct db_tdb_ctx);
189         return tdb_exists(ctx->wtdb->tdb, key);
190 }
191
192 static int db_tdb_wipe(struct db_context *db)
193 {
194         struct db_tdb_ctx *ctx = talloc_get_type_abort(
195                 db->private_data, struct db_tdb_ctx);
196         return tdb_wipe_all(ctx->wtdb->tdb);
197 }
198
199 static int db_tdb_parse(struct db_context *db, TDB_DATA key,
200                         int (*parser)(TDB_DATA key, TDB_DATA data,
201                                       void *private_data),
202                         void *private_data)
203 {
204         struct db_tdb_ctx *ctx = talloc_get_type_abort(
205                 db->private_data, struct db_tdb_ctx);
206
207         return tdb_parse_record(ctx->wtdb->tdb, key, parser, private_data) ? -1 : 0;
208 }
209
210 static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag)
211 {
212         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
213                                                        struct db_tdb_ctx);
214
215         /*
216          * This has a bug: We need to replace rec->value for correct
217          * operation, but right now brlock and locking don't use the value
218          * anymore after it was stored.
219          */
220
221         return (tdb_store(ctx->wtdb->tdb, rec->key, data, flag) == 0) ?
222                 NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
223 }
224
225 static NTSTATUS db_tdb_delete(struct db_record *rec)
226 {
227         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
228                                                        struct db_tdb_ctx);
229
230         if (tdb_delete(ctx->wtdb->tdb, rec->key) == 0) {
231                 return NT_STATUS_OK;
232         }
233
234         if (tdb_error(ctx->wtdb->tdb) == TDB_ERR_NOEXIST) {
235                 return NT_STATUS_NOT_FOUND;
236         }
237
238         return NT_STATUS_UNSUCCESSFUL;
239 }
240
241 struct db_tdb_traverse_ctx {
242         struct db_context *db;
243         int (*f)(struct db_record *rec, void *private_data);
244         void *private_data;
245 };
246
247 static int db_tdb_traverse_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
248                                 void *private_data)
249 {
250         struct db_tdb_traverse_ctx *ctx =
251                 (struct db_tdb_traverse_ctx *)private_data;
252         struct db_record rec;
253
254         rec.key = kbuf;
255         rec.value = dbuf;
256         rec.store = db_tdb_store;
257         rec.delete_rec = db_tdb_delete;
258         rec.private_data = ctx->db->private_data;
259
260         return ctx->f(&rec, ctx->private_data);
261 }
262
263 static int db_tdb_traverse(struct db_context *db,
264                            int (*f)(struct db_record *rec, void *private_data),
265                            void *private_data)
266 {
267         struct db_tdb_ctx *db_ctx =
268                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
269         struct db_tdb_traverse_ctx ctx;
270
271         ctx.db = db;
272         ctx.f = f;
273         ctx.private_data = private_data;
274         return tdb_traverse(db_ctx->wtdb->tdb, db_tdb_traverse_func, &ctx);
275 }
276
277 static NTSTATUS db_tdb_store_deny(struct db_record *rec, TDB_DATA data, int flag)
278 {
279         return NT_STATUS_MEDIA_WRITE_PROTECTED;
280 }
281
282 static NTSTATUS db_tdb_delete_deny(struct db_record *rec)
283 {
284         return NT_STATUS_MEDIA_WRITE_PROTECTED;
285 }
286
287 static int db_tdb_traverse_read_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
288                                 void *private_data)
289 {
290         struct db_tdb_traverse_ctx *ctx =
291                 (struct db_tdb_traverse_ctx *)private_data;
292         struct db_record rec;
293
294         rec.key = kbuf;
295         rec.value = dbuf;
296         rec.store = db_tdb_store_deny;
297         rec.delete_rec = db_tdb_delete_deny;
298         rec.private_data = ctx->db->private_data;
299
300         return ctx->f(&rec, ctx->private_data);
301 }
302
303 static int db_tdb_traverse_read(struct db_context *db,
304                            int (*f)(struct db_record *rec, void *private_data),
305                            void *private_data)
306 {
307         struct db_tdb_ctx *db_ctx =
308                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
309         struct db_tdb_traverse_ctx ctx;
310
311         ctx.db = db;
312         ctx.f = f;
313         ctx.private_data = private_data;
314         return tdb_traverse_read(db_ctx->wtdb->tdb, db_tdb_traverse_read_func, &ctx);
315 }
316
317 static int db_tdb_get_seqnum(struct db_context *db)
318
319 {
320         struct db_tdb_ctx *db_ctx =
321                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
322         return tdb_get_seqnum(db_ctx->wtdb->tdb);
323 }
324
325 static int db_tdb_get_flags(struct db_context *db)
326
327 {
328         struct db_tdb_ctx *db_ctx =
329                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
330         return tdb_get_flags(db_ctx->wtdb->tdb);
331 }
332
333 static int db_tdb_transaction_start(struct db_context *db)
334 {
335         struct db_tdb_ctx *db_ctx =
336                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
337         return tdb_transaction_start(db_ctx->wtdb->tdb) ? -1 : 0;
338 }
339
340 static int db_tdb_transaction_commit(struct db_context *db)
341 {
342         struct db_tdb_ctx *db_ctx =
343                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
344         return tdb_transaction_commit(db_ctx->wtdb->tdb) ? -1 : 0;
345 }
346
347 static int db_tdb_transaction_cancel(struct db_context *db)
348 {
349         struct db_tdb_ctx *db_ctx =
350                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
351         tdb_transaction_cancel(db_ctx->wtdb->tdb);
352         return 0;
353 }
354
355 struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
356                                const char *name,
357                                int hash_size, int tdb_flags,
358                                int open_flags, mode_t mode)
359 {
360         struct db_context *result = NULL;
361         struct db_tdb_ctx *db_tdb;
362
363         result = talloc_zero(mem_ctx, struct db_context);
364         if (result == NULL) {
365                 DEBUG(0, ("talloc failed\n"));
366                 goto fail;
367         }
368
369         result->private_data = db_tdb = talloc(result, struct db_tdb_ctx);
370         if (db_tdb == NULL) {
371                 DEBUG(0, ("talloc failed\n"));
372                 goto fail;
373         }
374
375         db_tdb->wtdb = tdb_wrap_open(db_tdb, name, hash_size, tdb_flags,
376                                      open_flags, mode);
377         if (db_tdb->wtdb == NULL) {
378                 DEBUG(3, ("Could not open tdb: %s\n", strerror(errno)));
379                 goto fail;
380         }
381
382         result->fetch_locked = db_tdb_fetch_locked;
383         result->fetch = db_tdb_fetch;
384         result->traverse = db_tdb_traverse;
385         result->traverse_read = db_tdb_traverse_read;
386         result->parse_record = db_tdb_parse;
387         result->get_seqnum = db_tdb_get_seqnum;
388         result->get_flags = db_tdb_get_flags;
389         result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
390         result->transaction_start = db_tdb_transaction_start;
391         result->transaction_commit = db_tdb_transaction_commit;
392         result->transaction_cancel = db_tdb_transaction_cancel;
393         result->exists = db_tdb_exists;
394         result->wipe = db_tdb_wipe;
395         return result;
396
397  fail:
398         if (result != NULL) {
399                 TALLOC_FREE(result);
400         }
401         return NULL;
402 }