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