b5eb1881d42169c6575d24327907761e04bc6ec6
[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 NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag)
180 {
181         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
182                                                        struct db_tdb_ctx);
183
184         /*
185          * This has a bug: We need to replace rec->value for correct
186          * operation, but right now brlock and locking don't use the value
187          * anymore after it was stored.
188          */
189
190         return (tdb_store(ctx->wtdb->tdb, rec->key, data, flag) == 0) ?
191                 NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL;
192 }
193
194 static NTSTATUS db_tdb_delete(struct db_record *rec)
195 {
196         struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
197                                                        struct db_tdb_ctx);
198
199         if (tdb_delete(ctx->wtdb->tdb, rec->key) == 0) {
200                 return NT_STATUS_OK;
201         }
202
203         if (tdb_error(ctx->wtdb->tdb) == TDB_ERR_NOEXIST) {
204                 return NT_STATUS_NOT_FOUND;
205         }
206
207         return NT_STATUS_UNSUCCESSFUL;
208 }
209
210 struct db_tdb_traverse_ctx {
211         struct db_context *db;
212         int (*f)(struct db_record *rec, void *private_data);
213         void *private_data;
214 };
215
216 static int db_tdb_traverse_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
217                                 void *private_data)
218 {
219         struct db_tdb_traverse_ctx *ctx =
220                 (struct db_tdb_traverse_ctx *)private_data;
221         struct db_record rec;
222
223         rec.key = kbuf;
224         rec.value = dbuf;
225         rec.store = db_tdb_store;
226         rec.delete_rec = db_tdb_delete;
227         rec.private_data = ctx->db->private_data;
228
229         return ctx->f(&rec, ctx->private_data);
230 }
231
232 static int db_tdb_traverse(struct db_context *db,
233                            int (*f)(struct db_record *rec, void *private_data),
234                            void *private_data)
235 {
236         struct db_tdb_ctx *db_ctx =
237                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
238         struct db_tdb_traverse_ctx ctx;
239
240         ctx.db = db;
241         ctx.f = f;
242         ctx.private_data = private_data;
243         return tdb_traverse(db_ctx->wtdb->tdb, db_tdb_traverse_func, &ctx);
244 }
245
246 static NTSTATUS db_tdb_store_deny(struct db_record *rec, TDB_DATA data, int flag)
247 {
248         return NT_STATUS_MEDIA_WRITE_PROTECTED;
249 }
250
251 static NTSTATUS db_tdb_delete_deny(struct db_record *rec)
252 {
253         return NT_STATUS_MEDIA_WRITE_PROTECTED;
254 }
255
256 static int db_tdb_traverse_read_func(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
257                                 void *private_data)
258 {
259         struct db_tdb_traverse_ctx *ctx =
260                 (struct db_tdb_traverse_ctx *)private_data;
261         struct db_record rec;
262
263         rec.key = kbuf;
264         rec.value = dbuf;
265         rec.store = db_tdb_store_deny;
266         rec.delete_rec = db_tdb_delete_deny;
267         rec.private_data = ctx->db->private_data;
268
269         return ctx->f(&rec, ctx->private_data);
270 }
271
272 static int db_tdb_traverse_read(struct db_context *db,
273                            int (*f)(struct db_record *rec, void *private_data),
274                            void *private_data)
275 {
276         struct db_tdb_ctx *db_ctx =
277                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
278         struct db_tdb_traverse_ctx ctx;
279
280         ctx.db = db;
281         ctx.f = f;
282         ctx.private_data = private_data;
283         return tdb_traverse_read(db_ctx->wtdb->tdb, db_tdb_traverse_read_func, &ctx);
284 }
285
286 static int db_tdb_get_seqnum(struct db_context *db)
287
288 {
289         struct db_tdb_ctx *db_ctx =
290                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
291         return tdb_get_seqnum(db_ctx->wtdb->tdb);
292 }
293
294 static int db_tdb_get_flags(struct db_context *db)
295
296 {
297         struct db_tdb_ctx *db_ctx =
298                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
299         return tdb_get_flags(db_ctx->wtdb->tdb);
300 }
301
302 static int db_tdb_transaction_start(struct db_context *db)
303 {
304         struct db_tdb_ctx *db_ctx =
305                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
306         return tdb_transaction_start(db_ctx->wtdb->tdb);
307 }
308
309 static int db_tdb_transaction_commit(struct db_context *db)
310 {
311         struct db_tdb_ctx *db_ctx =
312                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
313         return tdb_transaction_commit(db_ctx->wtdb->tdb);
314 }
315
316 static int db_tdb_transaction_cancel(struct db_context *db)
317 {
318         struct db_tdb_ctx *db_ctx =
319                 talloc_get_type_abort(db->private_data, struct db_tdb_ctx);
320         return tdb_transaction_cancel(db_ctx->wtdb->tdb);
321 }
322
323 struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
324                                const char *name,
325                                int hash_size, int tdb_flags,
326                                int open_flags, mode_t mode)
327 {
328         struct db_context *result = NULL;
329         struct db_tdb_ctx *db_tdb;
330
331         result = TALLOC_ZERO_P(mem_ctx, struct db_context);
332         if (result == NULL) {
333                 DEBUG(0, ("talloc failed\n"));
334                 goto fail;
335         }
336
337         result->private_data = db_tdb = TALLOC_P(result, struct db_tdb_ctx);
338         if (db_tdb == NULL) {
339                 DEBUG(0, ("talloc failed\n"));
340                 goto fail;
341         }
342
343         db_tdb->wtdb = tdb_wrap_open(db_tdb, name, hash_size, tdb_flags,
344                                      open_flags, mode);
345         if (db_tdb->wtdb == NULL) {
346                 DEBUG(3, ("Could not open tdb: %s\n", strerror(errno)));
347                 goto fail;
348         }
349
350         result->fetch_locked = db_tdb_fetch_locked;
351         result->fetch = db_tdb_fetch;
352         result->traverse = db_tdb_traverse;
353         result->traverse_read = db_tdb_traverse_read;
354         result->get_seqnum = db_tdb_get_seqnum;
355         result->get_flags = db_tdb_get_flags;
356         result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
357         result->transaction_start = db_tdb_transaction_start;
358         result->transaction_commit = db_tdb_transaction_commit;
359         result->transaction_cancel = db_tdb_transaction_cancel;
360         return result;
361
362  fail:
363         if (result != NULL) {
364                 TALLOC_FREE(result);
365         }
366         return NULL;
367 }