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