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