s3: only include tdb headers where needed.
[sfrench/samba-autobuild/.git] / source3 / lib / dbwrap_util.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Utility functions for the dbwrap API
4    Copyright (C) Volker Lendecke 2007
5    Copyright (C) Michael Adam 2009
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "dbwrap.h"
24 #include "util_tdb.h"
25
26 int32_t dbwrap_fetch_int32(struct db_context *db, const char *keystr)
27 {
28         TDB_DATA dbuf;
29         int32 ret;
30
31         if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
32                 return -1;
33         }
34
35         if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(int32_t))) {
36                 TALLOC_FREE(dbuf.dptr);
37                 return -1;
38         }
39
40         ret = IVAL(dbuf.dptr, 0);
41         TALLOC_FREE(dbuf.dptr);
42         return ret;
43 }
44
45 int dbwrap_store_int32(struct db_context *db, const char *keystr, int32_t v)
46 {
47         struct db_record *rec;
48         int32 v_store;
49         NTSTATUS status;
50
51         rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
52         if (rec == NULL) {
53                 return -1;
54         }
55
56         SIVAL(&v_store, 0, v);
57
58         status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
59                                                sizeof(v_store)),
60                             TDB_REPLACE);
61         TALLOC_FREE(rec);
62         return NT_STATUS_IS_OK(status) ? 0 : -1;
63 }
64
65 bool dbwrap_fetch_uint32(struct db_context *db, const char *keystr,
66                          uint32_t *val)
67 {
68         TDB_DATA dbuf;
69
70         if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
71                 return false;
72         }
73
74         if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(uint32_t))) {
75                 TALLOC_FREE(dbuf.dptr);
76                 return false;
77         }
78
79         *val = IVAL(dbuf.dptr, 0);
80         TALLOC_FREE(dbuf.dptr);
81         return true;
82 }
83
84 int dbwrap_store_uint32(struct db_context *db, const char *keystr, uint32_t v)
85 {
86         struct db_record *rec;
87         uint32 v_store;
88         NTSTATUS status;
89
90         rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
91         if (rec == NULL) {
92                 return -1;
93         }
94
95         SIVAL(&v_store, 0, v);
96
97         status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
98                                                sizeof(v_store)),
99                             TDB_REPLACE);
100         TALLOC_FREE(rec);
101         return NT_STATUS_IS_OK(status) ? 0 : -1;
102 }
103
104 /**
105  * Atomic unsigned integer change (addition):
106  *
107  * if value does not exist yet in the db, use *oldval as initial old value.
108  * return old value in *oldval.
109  * store *oldval + change_val to db.
110  */
111
112 struct dbwrap_change_uint32_atomic_context {
113         const char *keystr;
114         uint32_t *oldval;
115         uint32_t change_val;
116 };
117
118 static NTSTATUS dbwrap_change_uint32_atomic_action(struct db_context *db,
119                                                    void *private_data)
120 {
121         struct db_record *rec;
122         uint32_t val = (uint32_t)-1;
123         uint32_t v_store;
124         NTSTATUS ret;
125         struct dbwrap_change_uint32_atomic_context *state;
126
127         state = (struct dbwrap_change_uint32_atomic_context *)private_data;
128
129         rec = db->fetch_locked(db, NULL, string_term_tdb_data(state->keystr));
130         if (!rec) {
131                 return NT_STATUS_UNSUCCESSFUL;
132         }
133
134         if (rec->value.dptr == NULL) {
135                 val = *(state->oldval);
136         } else if (rec->value.dsize == sizeof(val)) {
137                 val = IVAL(rec->value.dptr, 0);
138                 *(state->oldval) = val;
139         } else {
140                 ret = NT_STATUS_UNSUCCESSFUL;
141                 goto done;
142         }
143
144         val += state->change_val;
145
146         SIVAL(&v_store, 0, val);
147
148         ret = rec->store(rec,
149                          make_tdb_data((const uint8 *)&v_store,
150                                        sizeof(v_store)),
151                          TDB_REPLACE);
152
153 done:
154         TALLOC_FREE(rec);
155         return ret;
156 }
157
158 NTSTATUS dbwrap_change_uint32_atomic(struct db_context *db, const char *keystr,
159                                      uint32_t *oldval, uint32_t change_val)
160 {
161         NTSTATUS ret;
162         struct dbwrap_change_uint32_atomic_context state;
163
164         state.keystr = keystr;
165         state.oldval = oldval;
166         state.change_val = change_val;
167
168         ret = dbwrap_change_uint32_atomic_action(db, &state);
169
170         return ret;
171 }
172
173 NTSTATUS dbwrap_trans_change_uint32_atomic(struct db_context *db,
174                                            const char *keystr,
175                                            uint32_t *oldval,
176                                            uint32_t change_val)
177 {
178         NTSTATUS ret;
179         struct dbwrap_change_uint32_atomic_context state;
180
181         state.keystr = keystr;
182         state.oldval = oldval;
183         state.change_val = change_val;
184
185         ret = dbwrap_trans_do(db, dbwrap_change_uint32_atomic_action, &state);
186
187         return ret;
188 }
189
190 /**
191  * Atomic integer change (addition):
192  *
193  * if value does not exist yet in the db, use *oldval as initial old value.
194  * return old value in *oldval.
195  * store *oldval + change_val to db.
196  */
197
198 struct dbwrap_change_int32_atomic_context {
199         const char *keystr;
200         int32_t *oldval;
201         int32_t change_val;
202 };
203
204 static NTSTATUS dbwrap_change_int32_atomic_action(struct db_context *db,
205                                                   void *private_data)
206 {
207         struct db_record *rec;
208         int32_t val = -1;
209         int32_t v_store;
210         NTSTATUS ret;
211         struct dbwrap_change_int32_atomic_context *state;
212
213         state = (struct dbwrap_change_int32_atomic_context *)private_data;
214
215         rec = db->fetch_locked(db, NULL, string_term_tdb_data(state->keystr));
216         if (!rec) {
217                 return NT_STATUS_UNSUCCESSFUL;
218         }
219
220         if (rec->value.dptr == NULL) {
221                 val = *(state->oldval);
222         } else if (rec->value.dsize == sizeof(val)) {
223                 val = IVAL(rec->value.dptr, 0);
224                 *(state->oldval) = val;
225         } else {
226                 ret = NT_STATUS_UNSUCCESSFUL;
227                 goto done;
228         }
229
230         val += state->change_val;
231
232         SIVAL(&v_store, 0, val);
233
234         ret = rec->store(rec,
235                          make_tdb_data((const uint8_t *)&v_store,
236                                        sizeof(v_store)),
237                          TDB_REPLACE);
238
239 done:
240         TALLOC_FREE(rec);
241         return ret;
242 }
243
244 NTSTATUS dbwrap_change_int32_atomic(struct db_context *db, const char *keystr,
245                                     int32_t *oldval, int32_t change_val)
246 {
247         NTSTATUS ret;
248         struct dbwrap_change_int32_atomic_context state;
249
250         state.keystr = keystr;
251         state.oldval = oldval;
252         state.change_val = change_val;
253
254         ret = dbwrap_change_int32_atomic_action(db, &state);
255
256         return ret;
257 }
258
259 NTSTATUS dbwrap_trans_change_int32_atomic(struct db_context *db,
260                                           const char *keystr,
261                                           int32_t *oldval,
262                                           int32_t change_val)
263 {
264         NTSTATUS ret;
265         struct dbwrap_change_int32_atomic_context state;
266
267         state.keystr = keystr;
268         state.oldval = oldval;
269         state.change_val = change_val;
270
271         ret = dbwrap_trans_do(db, dbwrap_change_int32_atomic_action, &state);
272
273         return ret;
274 }
275
276 struct dbwrap_store_context {
277         TDB_DATA *key;
278         TDB_DATA *dbuf;
279         int flag;
280 };
281
282 static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data)
283 {
284         struct db_record *rec = NULL;
285         NTSTATUS status;
286         struct dbwrap_store_context *store_ctx;
287
288         store_ctx = (struct dbwrap_store_context *)private_data;
289
290         rec = db->fetch_locked(db, talloc_tos(), *(store_ctx->key));
291         if (rec == NULL) {
292                 DEBUG(5, ("fetch_locked failed\n"));
293                 return NT_STATUS_NO_MEMORY;
294         }
295
296         status = rec->store(rec, *(store_ctx->dbuf), store_ctx->flag);
297         if (!NT_STATUS_IS_OK(status)) {
298                 DEBUG(5, ("store returned %s\n", nt_errstr(status)));
299         }
300
301         TALLOC_FREE(rec);
302         return status;
303 }
304
305 NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
306                             int flag)
307 {
308         NTSTATUS status;
309         struct dbwrap_store_context store_ctx;
310
311         store_ctx.key = &key;
312         store_ctx.dbuf = &dbuf;
313         store_ctx.flag = flag;
314
315         status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
316
317         return status;
318 }
319
320 static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
321 {
322         NTSTATUS status;
323         struct db_record *rec;
324         TDB_DATA *key = (TDB_DATA *)private_data;
325
326         rec = db->fetch_locked(db, talloc_tos(), *key);
327         if (rec == NULL) {
328                 DEBUG(5, ("fetch_locked failed\n"));
329                 return NT_STATUS_NO_MEMORY;
330         }
331
332         status = rec->delete_rec(rec);
333         if (!NT_STATUS_IS_OK(status)) {
334                 DEBUG(5, ("delete_rec returned %s\n", nt_errstr(status)));
335         }
336
337         talloc_free(rec);
338         return  status;
339 }
340
341 NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
342 {
343         NTSTATUS status;
344
345         status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
346
347         return status;
348 }
349
350 NTSTATUS dbwrap_trans_store_int32(struct db_context *db, const char *keystr,
351                                   int32_t v)
352 {
353         int32 v_store;
354
355         SIVAL(&v_store, 0, v);
356
357         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
358                                   make_tdb_data((const uint8 *)&v_store,
359                                                 sizeof(v_store)),
360                                   TDB_REPLACE);
361 }
362
363 NTSTATUS dbwrap_trans_store_uint32(struct db_context *db, const char *keystr,
364                                    uint32_t v)
365 {
366         uint32 v_store;
367
368         SIVAL(&v_store, 0, v);
369
370         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
371                                   make_tdb_data((const uint8 *)&v_store,
372                                                 sizeof(v_store)),
373                                   TDB_REPLACE);
374 }
375
376 NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
377                                      TDB_DATA data, int flags)
378 {
379         return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
380 }
381
382 NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
383 {
384         return dbwrap_trans_delete(db, string_term_tdb_data(key));
385 }
386
387 /**
388  * Wrap db action(s) into a transaction.
389  */
390 NTSTATUS dbwrap_trans_do(struct db_context *db,
391                          NTSTATUS (*action)(struct db_context *, void *),
392                          void *private_data)
393 {
394         int res;
395         NTSTATUS status;
396
397         res = db->transaction_start(db);
398         if (res != 0) {
399                 DEBUG(5, ("transaction_start failed\n"));
400                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
401         }
402
403         status = action(db, private_data);
404         if (!NT_STATUS_IS_OK(status)) {
405                 if (db->transaction_cancel(db) != 0) {
406                         smb_panic("Cancelling transaction failed");
407                 }
408                 return status;
409         }
410
411         res = db->transaction_commit(db);
412         if (res == 0) {
413                 return NT_STATUS_OK;
414         }
415
416         DEBUG(2, ("transaction_commit failed\n"));
417         return NT_STATUS_INTERNAL_DB_CORRUPTION;
418 }
419
420 struct dbwrap_trans_traverse_action_ctx {
421         int (*f)(struct db_record* rec, void* private_data);
422         void* private_data;
423 };
424
425
426 static NTSTATUS dbwrap_trans_traverse_action(struct db_context* db, void* private_data)
427 {
428         struct dbwrap_trans_traverse_action_ctx* ctx =
429                 (struct dbwrap_trans_traverse_action_ctx*)private_data;
430
431         int ret = db->traverse(db, ctx->f, ctx->private_data);
432
433         return (ret == -1) ? NT_STATUS_INTERNAL_DB_CORRUPTION : NT_STATUS_OK;
434 }
435
436 NTSTATUS dbwrap_trans_traverse(struct db_context *db,
437                                int (*f)(struct db_record*, void*),
438                                void *private_data)
439 {
440         struct dbwrap_trans_traverse_action_ctx ctx = {
441                 .f = f,
442                 .private_data = private_data,
443         };
444         return dbwrap_trans_do(db, dbwrap_trans_traverse_action, &ctx);
445 }
446
447 NTSTATUS dbwrap_traverse(struct db_context *db,
448                          int (*f)(struct db_record*, void*),
449                          void *private_data)
450 {
451         int ret = db->traverse(db, f, private_data);
452         return (ret == -1) ? NT_STATUS_INTERNAL_DB_CORRUPTION : NT_STATUS_OK;
453 }
454
455
456
457
458 NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
459 {
460         char *key_upper;
461         NTSTATUS status;
462
463         key_upper = talloc_strdup_upper(talloc_tos(), key);
464         if (key_upper == NULL) {
465                 return NT_STATUS_NO_MEMORY;
466         }
467
468         status = dbwrap_delete_bystring(db, key_upper);
469
470         talloc_free(key_upper);
471         return status;
472 }
473
474 NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
475                                      TDB_DATA data, int flags)
476 {
477         char *key_upper;
478         NTSTATUS status;
479
480         key_upper = talloc_strdup_upper(talloc_tos(), key);
481         if (key_upper == NULL) {
482                 return NT_STATUS_NO_MEMORY;
483         }
484
485         status = dbwrap_store_bystring(db, key_upper, data, flags);
486
487         talloc_free(key_upper);
488         return status;
489 }
490
491 TDB_DATA dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
492                                      const char *key)
493 {
494         char *key_upper;
495         TDB_DATA result;
496
497         key_upper = talloc_strdup_upper(talloc_tos(), key);
498         if (key_upper == NULL) {
499                 return make_tdb_data(NULL, 0);
500         }
501
502         result = dbwrap_fetch_bystring(db, mem_ctx, key_upper);
503
504         talloc_free(key_upper);
505         return result;
506 }