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