96888a4fb0bd20f01782255c5fd5124aa2cb9f52
[gd/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    
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
24 int32_t dbwrap_fetch_int32(struct db_context *db, const char *keystr)
25 {
26         TDB_DATA dbuf;
27         int32 ret;
28
29         if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
30                 return -1;
31         }
32
33         if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(int32_t))) {
34                 TALLOC_FREE(dbuf.dptr);
35                 return -1;
36         }
37
38         ret = IVAL(dbuf.dptr, 0);
39         TALLOC_FREE(dbuf.dptr);
40         return ret;
41 }
42
43 int dbwrap_store_int32(struct db_context *db, const char *keystr, int32_t v)
44 {
45         struct db_record *rec;
46         int32 v_store;
47         NTSTATUS status;
48
49         rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
50         if (rec == NULL) {
51                 return -1;
52         }
53
54         SIVAL(&v_store, 0, v);
55
56         status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
57                                                sizeof(v_store)),
58                             TDB_REPLACE);
59         TALLOC_FREE(rec);
60         return NT_STATUS_IS_OK(status) ? 0 : -1;
61 }
62
63 bool dbwrap_fetch_uint32(struct db_context *db, const char *keystr,
64                          uint32_t *val)
65 {
66         TDB_DATA dbuf;
67
68         if (db->fetch(db, NULL, string_term_tdb_data(keystr), &dbuf) != 0) {
69                 return false;
70         }
71
72         if ((dbuf.dptr == NULL) || (dbuf.dsize != sizeof(uint32_t))) {
73                 TALLOC_FREE(dbuf.dptr);
74                 return false;
75         }
76
77         *val = IVAL(dbuf.dptr, 0);
78         TALLOC_FREE(dbuf.dptr);
79         return true;
80 }
81
82 int dbwrap_store_uint32(struct db_context *db, const char *keystr, uint32_t v)
83 {
84         struct db_record *rec;
85         uint32 v_store;
86         NTSTATUS status;
87
88         rec = db->fetch_locked(db, NULL, string_term_tdb_data(keystr));
89         if (rec == NULL) {
90                 return -1;
91         }
92
93         SIVAL(&v_store, 0, v);
94
95         status = rec->store(rec, make_tdb_data((const uint8 *)&v_store,
96                                                sizeof(v_store)),
97                             TDB_REPLACE);
98         TALLOC_FREE(rec);
99         return NT_STATUS_IS_OK(status) ? 0 : -1;
100 }
101
102 /**
103  * Atomic unsigned integer change (addition):
104  *
105  * if value does not exist yet in the db, use *oldval as initial old value.
106  * return old value in *oldval.
107  * store *oldval + change_val to db.
108  */
109
110 struct dbwrap_change_uint32_atomic_context {
111         const char *keystr;
112         uint32_t *oldval;
113         uint32_t change_val;
114 };
115
116 static NTSTATUS dbwrap_change_uint32_atomic_action(struct db_context *db,
117                                                    void *private_data)
118 {
119         struct db_record *rec;
120         uint32 val = -1;
121         uint32_t v_store;
122         NTSTATUS ret;
123         struct dbwrap_change_uint32_atomic_context *state;
124
125         state = (struct dbwrap_change_uint32_atomic_context *)private_data;
126
127         rec = db->fetch_locked(db, NULL, string_term_tdb_data(state->keystr));
128         if (!rec) {
129                 return NT_STATUS_UNSUCCESSFUL;
130         }
131
132         if (rec->value.dptr == NULL) {
133                 val = *(state->oldval);
134         } else if (rec->value.dsize == sizeof(val)) {
135                 val = IVAL(rec->value.dptr, 0);
136                 *(state->oldval) = val;
137         } else {
138                 ret = NT_STATUS_UNSUCCESSFUL;
139                 goto done;
140         }
141
142         val += state->change_val;
143
144         SIVAL(&v_store, 0, val);
145
146         ret = rec->store(rec,
147                          make_tdb_data((const uint8 *)&v_store,
148                                        sizeof(v_store)),
149                          TDB_REPLACE);
150
151 done:
152         TALLOC_FREE(rec);
153         return ret;
154 }
155
156 NTSTATUS dbwrap_change_uint32_atomic(struct db_context *db, const char *keystr,
157                                      uint32_t *oldval, uint32_t change_val)
158 {
159         NTSTATUS ret;
160         struct dbwrap_change_uint32_atomic_context state;
161
162         state.keystr = keystr;
163         state.oldval = oldval;
164         state.change_val = change_val;
165
166         ret = dbwrap_change_uint32_atomic_action(db, &state);
167
168         return ret;
169 }
170
171 NTSTATUS dbwrap_trans_change_uint32_atomic(struct db_context *db,
172                                            const char *keystr,
173                                            uint32_t *oldval,
174                                            uint32_t change_val)
175 {
176         NTSTATUS ret;
177         struct dbwrap_change_uint32_atomic_context state;
178
179         state.keystr = keystr;
180         state.oldval = oldval;
181         state.change_val = change_val;
182
183         ret = dbwrap_trans_do(db, dbwrap_change_uint32_atomic_action, &state);
184
185         return ret;
186 }
187
188 /**
189  * Atomic integer change (addition):
190  *
191  * if value does not exist yet in the db, use *oldval as initial old value.
192  * return old value in *oldval.
193  * store *oldval + change_val to db.
194  */
195
196 struct dbwrap_change_int32_atomic_context {
197         const char *keystr;
198         int32_t *oldval;
199         int32_t change_val;
200 };
201
202 static NTSTATUS dbwrap_change_int32_atomic_action(struct db_context *db,
203                                                   void *private_data)
204 {
205         struct db_record *rec;
206         int32_t val = -1;
207         TDB_DATA data;
208         NTSTATUS ret;
209         struct dbwrap_change_int32_atomic_context *state;
210
211         state = (struct dbwrap_change_int32_atomic_context *)private_data;
212
213         rec = db->fetch_locked(db, NULL, string_term_tdb_data(state->keystr));
214         if (!rec) {
215                 return NT_STATUS_UNSUCCESSFUL;
216         }
217
218         if (rec->value.dptr == NULL) {
219                 val = *(state->oldval);
220         } else if (rec->value.dsize == sizeof(val)) {
221                 val = IVAL(rec->value.dptr, 0);
222                 *(state->oldval) = val;
223         } else {
224                 ret = NT_STATUS_UNSUCCESSFUL;
225                 goto done;
226         }
227
228         val += state->change_val;
229
230         data.dsize = sizeof(val);
231         data.dptr = (uint8 *)&val;
232
233         ret = rec->store(rec, data, TDB_REPLACE);
234
235 done:
236         TALLOC_FREE(rec);
237         return ret;
238 }
239
240 NTSTATUS dbwrap_change_int32_atomic(struct db_context *db, const char *keystr,
241                                     int32_t *oldval, int32_t change_val)
242 {
243         NTSTATUS ret;
244         struct dbwrap_change_int32_atomic_context state;
245
246         state.keystr = keystr;
247         state.oldval = oldval;
248         state.change_val = change_val;
249
250         ret = dbwrap_change_int32_atomic_action(db, &state);
251
252         return ret;
253 }
254
255 NTSTATUS dbwrap_trans_change_int32_atomic(struct db_context *db,
256                                           const char *keystr,
257                                           int32_t *oldval,
258                                           int32_t change_val)
259 {
260         NTSTATUS ret;
261         struct dbwrap_change_int32_atomic_context state;
262
263         state.keystr = keystr;
264         state.oldval = oldval;
265         state.change_val = change_val;
266
267         ret = dbwrap_trans_do(db, dbwrap_change_int32_atomic_action, &state);
268
269         return ret;
270 }
271
272 struct dbwrap_store_context {
273         TDB_DATA *key;
274         TDB_DATA *dbuf;
275         int flag;
276 };
277
278 static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data)
279 {
280         struct db_record *rec = NULL;
281         NTSTATUS status;
282         struct dbwrap_store_context *store_ctx;
283
284         store_ctx = (struct dbwrap_store_context *)private_data;
285
286         rec = db->fetch_locked(db, talloc_tos(), *(store_ctx->key));
287         if (rec == NULL) {
288                 DEBUG(5, ("fetch_locked failed\n"));
289                 return NT_STATUS_NO_MEMORY;
290         }
291
292         status = rec->store(rec, *(store_ctx->dbuf), store_ctx->flag);
293         if (!NT_STATUS_IS_OK(status)) {
294                 DEBUG(5, ("store returned %s\n", nt_errstr(status)));
295         }
296
297         TALLOC_FREE(rec);
298         return status;
299 }
300
301 NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
302                             int flag)
303 {
304         NTSTATUS status;
305         struct dbwrap_store_context store_ctx;
306
307         store_ctx.key = &key;
308         store_ctx.dbuf = &dbuf;
309         store_ctx.flag = flag;
310
311         status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
312
313         return status;
314 }
315
316 static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
317 {
318         NTSTATUS status;
319         struct db_record *rec;
320         TDB_DATA *key = (TDB_DATA *)private_data;
321
322         rec = db->fetch_locked(db, talloc_tos(), *key);
323         if (rec == NULL) {
324                 DEBUG(5, ("fetch_locked failed\n"));
325                 return NT_STATUS_NO_MEMORY;
326         }
327
328         status = rec->delete_rec(rec);
329         if (!NT_STATUS_IS_OK(status)) {
330                 DEBUG(5, ("delete_rec returned %s\n", nt_errstr(status)));
331         }
332
333         talloc_free(rec);
334         return  status;
335 }
336
337 NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
338 {
339         NTSTATUS status;
340
341         status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
342
343         return status;
344 }
345
346 NTSTATUS dbwrap_trans_store_int32(struct db_context *db, const char *keystr,
347                                   int32_t v)
348 {
349         int32 v_store;
350
351         SIVAL(&v_store, 0, v);
352
353         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
354                                   make_tdb_data((const uint8 *)&v_store,
355                                                 sizeof(v_store)),
356                                   TDB_REPLACE);
357 }
358
359 NTSTATUS dbwrap_trans_store_uint32(struct db_context *db, const char *keystr,
360                                    uint32_t v)
361 {
362         uint32 v_store;
363
364         SIVAL(&v_store, 0, v);
365
366         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
367                                   make_tdb_data((const uint8 *)&v_store,
368                                                 sizeof(v_store)),
369                                   TDB_REPLACE);
370 }
371
372 NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
373                                      TDB_DATA data, int flags)
374 {
375         return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
376 }
377
378 NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
379 {
380         return dbwrap_trans_delete(db, string_term_tdb_data(key));
381 }
382
383 /**
384  * Wrap db action(s) into a transaction.
385  */
386 NTSTATUS dbwrap_trans_do(struct db_context *db,
387                          NTSTATUS (*action)(struct db_context *, void *),
388                          void *private_data)
389 {
390         int res;
391         NTSTATUS status;
392
393         res = db->transaction_start(db);
394         if (res != 0) {
395                 DEBUG(5, ("transaction_start failed\n"));
396                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
397         }
398
399         status = action(db, private_data);
400         if (!NT_STATUS_IS_OK(status)) {
401                 if (db->transaction_cancel(db) != 0) {
402                         smb_panic("Cancelling transaction failed");
403                 }
404                 return status;
405         }
406
407         res = db->transaction_commit(db);
408         if (res == 0) {
409                 return NT_STATUS_OK;
410         }
411
412         DEBUG(2, ("transaction_commit failed\n"));
413         return NT_STATUS_INTERNAL_DB_CORRUPTION;
414 }
415
416 NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
417 {
418         char *key_upper;
419         NTSTATUS status;
420
421         key_upper = talloc_strdup_upper(talloc_tos(), key);
422         if (key_upper == NULL) {
423                 return NT_STATUS_NO_MEMORY;
424         }
425
426         status = dbwrap_delete_bystring(db, key_upper);
427
428         talloc_free(key_upper);
429         return status;
430 }
431
432 NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
433                                      TDB_DATA data, int flags)
434 {
435         char *key_upper;
436         NTSTATUS status;
437
438         key_upper = talloc_strdup_upper(talloc_tos(), key);
439         if (key_upper == NULL) {
440                 return NT_STATUS_NO_MEMORY;
441         }
442
443         status = dbwrap_store_bystring(db, key_upper, data, flags);
444
445         talloc_free(key_upper);
446         return status;
447 }
448
449 TDB_DATA dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
450                                      const char *key)
451 {
452         char *key_upper;
453         TDB_DATA result;
454
455         key_upper = talloc_strdup_upper(talloc_tos(), key);
456         if (key_upper == NULL) {
457                 return make_tdb_data(NULL, 0);
458         }
459
460         result = dbwrap_fetch_bystring(db, mem_ctx, key_upper);
461
462         talloc_free(key_upper);
463         return result;
464 }