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