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