Merge branch 'master' of ssh://jht@git.samba.org/data/git/samba
[ira/wip.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 uint32_t dbwrap_change_uint32_atomic(struct db_context *db, const char *keystr,
110                                      uint32_t *oldval, uint32_t change_val)
111 {
112         struct db_record *rec;
113         uint32 val = -1;
114         TDB_DATA data;
115
116         if (!(rec = db->fetch_locked(db, NULL,
117                                      string_term_tdb_data(keystr)))) {
118                 return -1;
119         }
120
121         if (rec->value.dptr == NULL) {
122                 val = *oldval;
123         } else if (rec->value.dsize == sizeof(val)) {
124                 val = IVAL(rec->value.dptr, 0);
125                 *oldval = val;
126         } else {
127                 return -1;
128         }
129
130         val += change_val;
131
132         data.dsize = sizeof(val);
133         data.dptr = (uint8 *)&val;
134
135         rec->store(rec, data, TDB_REPLACE);
136
137         TALLOC_FREE(rec);
138
139         return 0;
140 }
141
142 /**
143  * Atomic 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 int32 dbwrap_change_int32_atomic(struct db_context *db, const char *keystr,
150                                  int32 *oldval, int32 change_val)
151 {
152         struct db_record *rec;
153         int32 val = -1;
154         TDB_DATA data;
155
156         if (!(rec = db->fetch_locked(db, NULL,
157                                      string_term_tdb_data(keystr)))) {
158                 return -1;
159         }
160
161         if (rec->value.dptr == NULL) {
162                 val = *oldval;
163         } else if (rec->value.dsize == sizeof(val)) {
164                 val = IVAL(rec->value.dptr, 0);
165                 *oldval = val;
166         } else {
167                 return -1;
168         }
169
170         val += change_val;
171
172         data.dsize = sizeof(val);
173         data.dptr = (uint8 *)&val;
174
175         rec->store(rec, data, TDB_REPLACE);
176
177         TALLOC_FREE(rec);
178
179         return 0;
180 }
181
182 struct dbwrap_store_context {
183         TDB_DATA *key;
184         TDB_DATA *dbuf;
185         int flag;
186 };
187
188 static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data)
189 {
190         struct db_record *rec = NULL;
191         NTSTATUS status;
192         struct dbwrap_store_context *store_ctx;
193
194         store_ctx = (struct dbwrap_store_context *)private_data;
195
196         rec = db->fetch_locked(db, talloc_tos(), *(store_ctx->key));
197         if (rec == NULL) {
198                 DEBUG(5, ("fetch_locked failed\n"));
199                 return NT_STATUS_NO_MEMORY;
200         }
201
202         status = rec->store(rec, *(store_ctx->dbuf), store_ctx->flag);
203         if (!NT_STATUS_IS_OK(status)) {
204                 DEBUG(5, ("store returned %s\n", nt_errstr(status)));
205         }
206
207         TALLOC_FREE(rec);
208         return status;
209 }
210
211 NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf,
212                             int flag)
213 {
214         NTSTATUS status;
215         struct dbwrap_store_context store_ctx;
216
217         store_ctx.key = &key;
218         store_ctx.dbuf = &dbuf;
219         store_ctx.flag = flag;
220
221         status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx);
222
223         return status;
224 }
225
226 static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data)
227 {
228         NTSTATUS status;
229         struct db_record *rec;
230         TDB_DATA *key = (TDB_DATA *)private_data;
231
232         rec = db->fetch_locked(db, talloc_tos(), *key);
233         if (rec == NULL) {
234                 DEBUG(5, ("fetch_locked failed\n"));
235                 return NT_STATUS_NO_MEMORY;
236         }
237
238         status = rec->delete_rec(rec);
239         if (!NT_STATUS_IS_OK(status)) {
240                 DEBUG(5, ("delete_rec returned %s\n", nt_errstr(status)));
241         }
242
243         talloc_free(rec);
244         return  status;
245 }
246
247 NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key)
248 {
249         NTSTATUS status;
250
251         status = dbwrap_trans_do(db, dbwrap_delete_action, &key);
252
253         return status;
254 }
255
256 NTSTATUS dbwrap_trans_store_int32(struct db_context *db, const char *keystr,
257                                   int32_t v)
258 {
259         int32 v_store;
260
261         SIVAL(&v_store, 0, v);
262
263         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
264                                   make_tdb_data((const uint8 *)&v_store,
265                                                 sizeof(v_store)),
266                                   TDB_REPLACE);
267 }
268
269 NTSTATUS dbwrap_trans_store_uint32(struct db_context *db, const char *keystr,
270                                    uint32_t v)
271 {
272         uint32 v_store;
273
274         SIVAL(&v_store, 0, v);
275
276         return dbwrap_trans_store(db, string_term_tdb_data(keystr),
277                                   make_tdb_data((const uint8 *)&v_store,
278                                                 sizeof(v_store)),
279                                   TDB_REPLACE);
280 }
281
282 NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key,
283                                      TDB_DATA data, int flags)
284 {
285         return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags);
286 }
287
288 NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key)
289 {
290         return dbwrap_trans_delete(db, string_term_tdb_data(key));
291 }
292
293 /**
294  * Wrap db action(s) into a transaction.
295  */
296 NTSTATUS dbwrap_trans_do(struct db_context *db,
297                          NTSTATUS (*action)(struct db_context *, void *),
298                          void *private_data)
299 {
300         int res;
301         NTSTATUS status;
302
303         res = db->transaction_start(db);
304         if (res != 0) {
305                 DEBUG(5, ("transaction_start failed\n"));
306                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
307         }
308
309         status = action(db, private_data);
310         if (!NT_STATUS_IS_OK(status)) {
311                 if (db->transaction_cancel(db) != 0) {
312                         smb_panic("Cancelling transaction failed");
313                 }
314                 return status;
315         }
316
317         res = db->transaction_commit(db);
318         if (res == 0) {
319                 return NT_STATUS_OK;
320         }
321
322         DEBUG(2, ("transaction_commit failed\n"));
323         return NT_STATUS_INTERNAL_DB_CORRUPTION;
324 }
325
326 NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key)
327 {
328         char *key_upper;
329         NTSTATUS status;
330
331         key_upper = talloc_strdup_upper(talloc_tos(), key);
332         if (key_upper == NULL) {
333                 return NT_STATUS_NO_MEMORY;
334         }
335
336         status = dbwrap_delete_bystring(db, key_upper);
337
338         talloc_free(key_upper);
339         return status;
340 }
341
342 NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key,
343                                      TDB_DATA data, int flags)
344 {
345         char *key_upper;
346         NTSTATUS status;
347
348         key_upper = talloc_strdup_upper(talloc_tos(), key);
349         if (key_upper == NULL) {
350                 return NT_STATUS_NO_MEMORY;
351         }
352
353         status = dbwrap_store_bystring(db, key_upper, data, flags);
354
355         talloc_free(key_upper);
356         return status;
357 }
358
359 TDB_DATA dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx,
360                                      const char *key)
361 {
362         char *key_upper;
363         TDB_DATA result;
364
365         key_upper = talloc_strdup_upper(talloc_tos(), key);
366         if (key_upper == NULL) {
367                 return make_tdb_data(NULL, 0);
368         }
369
370         result = dbwrap_fetch_bystring(db, mem_ctx, key_upper);
371
372         talloc_free(key_upper);
373         return result;
374 }