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 24int32_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 43int 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 63bool 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 82int 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 110struct dbwrap_change_uint32_atomic_context { 111 const char *keystr; 112 uint32_t *oldval; 113 uint32_t change_val; 114}; 115 116static 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 151done: 152 TALLOC_FREE(rec); 153 return ret; 154} 155 156NTSTATUS 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 171NTSTATUS 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 196struct dbwrap_change_int32_atomic_context { 197 const char *keystr; 198 int32_t *oldval; 199 int32_t change_val; 200}; 201 202static 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 int32_t v_store; 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 SIVAL(&v_store, 0, val); 231 232 ret = rec->store(rec, 233 make_tdb_data((const uint8_t *)&v_store, 234 sizeof(v_store)), 235 TDB_REPLACE); 236 237done: 238 TALLOC_FREE(rec); 239 return ret; 240} 241 242NTSTATUS dbwrap_change_int32_atomic(struct db_context *db, const char *keystr, 243 int32_t *oldval, int32_t change_val) 244{ 245 NTSTATUS ret; 246 struct dbwrap_change_int32_atomic_context state; 247 248 state.keystr = keystr; 249 state.oldval = oldval; 250 state.change_val = change_val; 251 252 ret = dbwrap_change_int32_atomic_action(db, &state); 253 254 return ret; 255} 256 257NTSTATUS dbwrap_trans_change_int32_atomic(struct db_context *db, 258 const char *keystr, 259 int32_t *oldval, 260 int32_t change_val) 261{ 262 NTSTATUS ret; 263 struct dbwrap_change_int32_atomic_context state; 264 265 state.keystr = keystr; 266 state.oldval = oldval; 267 state.change_val = change_val; 268 269 ret = dbwrap_trans_do(db, dbwrap_change_int32_atomic_action, &state); 270 271 return ret; 272} 273 274struct dbwrap_store_context { 275 TDB_DATA *key; 276 TDB_DATA *dbuf; 277 int flag; 278}; 279 280static NTSTATUS dbwrap_store_action(struct db_context *db, void *private_data) 281{ 282 struct db_record *rec = NULL; 283 NTSTATUS status; 284 struct dbwrap_store_context *store_ctx; 285 286 store_ctx = (struct dbwrap_store_context *)private_data; 287 288 rec = db->fetch_locked(db, talloc_tos(), *(store_ctx->key)); 289 if (rec == NULL) { 290 DEBUG(5, ("fetch_locked failed\n")); 291 return NT_STATUS_NO_MEMORY; 292 } 293 294 status = rec->store(rec, *(store_ctx->dbuf), store_ctx->flag); 295 if (!NT_STATUS_IS_OK(status)) { 296 DEBUG(5, ("store returned %s\n", nt_errstr(status))); 297 } 298 299 TALLOC_FREE(rec); 300 return status; 301} 302 303NTSTATUS dbwrap_trans_store(struct db_context *db, TDB_DATA key, TDB_DATA dbuf, 304 int flag) 305{ 306 NTSTATUS status; 307 struct dbwrap_store_context store_ctx; 308 309 store_ctx.key = &key; 310 store_ctx.dbuf = &dbuf; 311 store_ctx.flag = flag; 312 313 status = dbwrap_trans_do(db, dbwrap_store_action, &store_ctx); 314 315 return status; 316} 317 318static NTSTATUS dbwrap_delete_action(struct db_context * db, void *private_data) 319{ 320 NTSTATUS status; 321 struct db_record *rec; 322 TDB_DATA *key = (TDB_DATA *)private_data; 323 324 rec = db->fetch_locked(db, talloc_tos(), *key); 325 if (rec == NULL) { 326 DEBUG(5, ("fetch_locked failed\n")); 327 return NT_STATUS_NO_MEMORY; 328 } 329 330 status = rec->delete_rec(rec); 331 if (!NT_STATUS_IS_OK(status)) { 332 DEBUG(5, ("delete_rec returned %s\n", nt_errstr(status))); 333 } 334 335 talloc_free(rec); 336 return status; 337} 338 339NTSTATUS dbwrap_trans_delete(struct db_context *db, TDB_DATA key) 340{ 341 NTSTATUS status; 342 343 status = dbwrap_trans_do(db, dbwrap_delete_action, &key); 344 345 return status; 346} 347 348NTSTATUS dbwrap_trans_store_int32(struct db_context *db, const char *keystr, 349 int32_t v) 350{ 351 int32 v_store; 352 353 SIVAL(&v_store, 0, v); 354 355 return dbwrap_trans_store(db, string_term_tdb_data(keystr), 356 make_tdb_data((const uint8 *)&v_store, 357 sizeof(v_store)), 358 TDB_REPLACE); 359} 360 361NTSTATUS dbwrap_trans_store_uint32(struct db_context *db, const char *keystr, 362 uint32_t v) 363{ 364 uint32 v_store; 365 366 SIVAL(&v_store, 0, v); 367 368 return dbwrap_trans_store(db, string_term_tdb_data(keystr), 369 make_tdb_data((const uint8 *)&v_store, 370 sizeof(v_store)), 371 TDB_REPLACE); 372} 373 374NTSTATUS dbwrap_trans_store_bystring(struct db_context *db, const char *key, 375 TDB_DATA data, int flags) 376{ 377 return dbwrap_trans_store(db, string_term_tdb_data(key), data, flags); 378} 379 380NTSTATUS dbwrap_trans_delete_bystring(struct db_context *db, const char *key) 381{ 382 return dbwrap_trans_delete(db, string_term_tdb_data(key)); 383} 384 385/** 386 * Wrap db action(s) into a transaction. 387 */ 388NTSTATUS dbwrap_trans_do(struct db_context *db, 389 NTSTATUS (*action)(struct db_context *, void *), 390 void *private_data) 391{ 392 int res; 393 NTSTATUS status; 394 395 res = db->transaction_start(db); 396 if (res != 0) { 397 DEBUG(5, ("transaction_start failed\n")); 398 return NT_STATUS_INTERNAL_DB_CORRUPTION; 399 } 400 401 status = action(db, private_data); 402 if (!NT_STATUS_IS_OK(status)) { 403 if (db->transaction_cancel(db) != 0) { 404 smb_panic("Cancelling transaction failed"); 405 } 406 return status; 407 } 408 409 res = db->transaction_commit(db); 410 if (res == 0) { 411 return NT_STATUS_OK; 412 } 413 414 DEBUG(2, ("transaction_commit failed\n")); 415 return NT_STATUS_INTERNAL_DB_CORRUPTION; 416} 417 418NTSTATUS dbwrap_delete_bystring_upper(struct db_context *db, const char *key) 419{ 420 char *key_upper; 421 NTSTATUS status; 422 423 key_upper = talloc_strdup_upper(talloc_tos(), key); 424 if (key_upper == NULL) { 425 return NT_STATUS_NO_MEMORY; 426 } 427 428 status = dbwrap_delete_bystring(db, key_upper); 429 430 talloc_free(key_upper); 431 return status; 432} 433 434NTSTATUS dbwrap_store_bystring_upper(struct db_context *db, const char *key, 435 TDB_DATA data, int flags) 436{ 437 char *key_upper; 438 NTSTATUS status; 439 440 key_upper = talloc_strdup_upper(talloc_tos(), key); 441 if (key_upper == NULL) { 442 return NT_STATUS_NO_MEMORY; 443 } 444 445 status = dbwrap_store_bystring(db, key_upper, data, flags); 446 447 talloc_free(key_upper); 448 return status; 449} 450 451TDB_DATA dbwrap_fetch_bystring_upper(struct db_context *db, TALLOC_CTX *mem_ctx, 452 const char *key) 453{ 454 char *key_upper; 455 TDB_DATA result; 456 457 key_upper = talloc_strdup_upper(talloc_tos(), key); 458 if (key_upper == NULL) { 459 return make_tdb_data(NULL, 0); 460 } 461 462 result = dbwrap_fetch_bystring(db, mem_ctx, key_upper); 463 464 talloc_free(key_upper); 465 return result; 466} 467