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