LCOV - code coverage report
Current view: top level - lib/util - util_tdb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 125 220 56.8 %
Date: 2024-04-21 15:09:00 Functions: 27 29 93.1 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    tdb utility functions
       5             : 
       6             :    Copyright (C) Andrew Tridgell 1992-2006
       7             :    Copyright (C) Volker Lendecke 2007-2011
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "replace.h"
      24             : #include <talloc.h>
      25             : #include "libcli/util/ntstatus.h"
      26             : #include "lib/util/memory.h"
      27             : #include "lib/util/byteorder.h"
      28             : #include "system/filesys.h"
      29             : #include "../lib/tdb/include/tdb.h"
      30             : #include "../lib/util/util_tdb.h"
      31             : 
      32             : /* these are little tdb utility functions that are meant to make
      33             :    dealing with a tdb database a little less cumbersome in Samba */
      34             : 
      35             : /***************************************************************
      36             :  Make a TDB_DATA and keep the const warning in one place
      37             : ****************************************************************/
      38             : 
      39    95460295 : TDB_DATA make_tdb_data(const uint8_t *dptr, size_t dsize)
      40             : {
      41     1296939 :         TDB_DATA ret;
      42    95460295 :         ret.dptr = discard_const_p(uint8_t, dptr);
      43    95460295 :         ret.dsize = dsize;
      44    95460295 :         return ret;
      45             : }
      46             : 
      47           6 : bool tdb_data_equal(TDB_DATA t1, TDB_DATA t2)
      48             : {
      49           6 :         if (t1.dsize != t2.dsize) {
      50           2 :                 return false;
      51             :         }
      52           4 :         return (memcmp(t1.dptr, t2.dptr, t1.dsize) == 0);
      53             : }
      54             : 
      55        2880 : bool tdb_data_is_empty(TDB_DATA d)
      56             : {
      57        2880 :         return (d.dsize == 0) || (d.dptr == NULL);
      58             : }
      59             : 
      60      350960 : TDB_DATA string_tdb_data(const char *string)
      61             : {
      62      350960 :         return make_tdb_data((const uint8_t *)string, string ? strlen(string) : 0 );
      63             : }
      64             : 
      65    16794199 : TDB_DATA string_term_tdb_data(const char *string)
      66             : {
      67    16794199 :         return make_tdb_data((const uint8_t *)string, string ? strlen(string) + 1 : 0);
      68             : }
      69             : 
      70        4775 : TDB_DATA tdb_data_talloc_copy(TALLOC_CTX* mem_ctx, TDB_DATA data) {
      71        4849 :         TDB_DATA ret = {
      72        4775 :                 .dptr  = (uint8_t *)talloc_size(mem_ctx, data.dsize+1),
      73        4701 :                 .dsize = data.dsize
      74             :         };
      75        4775 :         if (ret.dptr == NULL) {
      76           0 :                 ret.dsize = 0;
      77             :         } else {
      78        4775 :                 memcpy(ret.dptr, data.dptr, data.dsize);
      79        4775 :                 ret.dptr[ret.dsize] = '\0';
      80             :         }
      81        4775 :         return ret;
      82             : }
      83             : 
      84             : 
      85             : /****************************************************************************
      86             :  Lock a chain by string. Return non-zero if lock failed.
      87             : ****************************************************************************/
      88             : 
      89        1476 : int tdb_lock_bystring(struct tdb_context *tdb, const char *keyval)
      90             : {
      91        1476 :         TDB_DATA key = string_term_tdb_data(keyval);
      92             : 
      93        1476 :         return tdb_chainlock(tdb, key);
      94             : }
      95             : 
      96             : /****************************************************************************
      97             :  Unlock a chain by string.
      98             : ****************************************************************************/
      99             : 
     100       23962 : void tdb_unlock_bystring(struct tdb_context *tdb, const char *keyval)
     101             : {
     102       23962 :         TDB_DATA key = string_term_tdb_data(keyval);
     103             : 
     104       23962 :         tdb_chainunlock(tdb, key);
     105       23962 : }
     106             : 
     107             : /****************************************************************************
     108             :  Read lock a chain by string. Return non-zero if lock failed.
     109             : ****************************************************************************/
     110             : 
     111           0 : int tdb_read_lock_bystring(struct tdb_context *tdb, const char *keyval)
     112             : {
     113           0 :         TDB_DATA key = string_term_tdb_data(keyval);
     114             : 
     115           0 :         return tdb_chainlock_read(tdb, key);
     116             : }
     117             : 
     118             : /****************************************************************************
     119             :  Read unlock a chain by string.
     120             : ****************************************************************************/
     121             : 
     122         236 : void tdb_read_unlock_bystring(struct tdb_context *tdb, const char *keyval)
     123             : {
     124         236 :         TDB_DATA key = string_term_tdb_data(keyval);
     125             : 
     126         236 :         tdb_chainunlock_read(tdb, key);
     127         236 : }
     128             : 
     129             : 
     130             : /****************************************************************************
     131             :  Fetch a int32_t value by a arbitrary blob key, return -1 if not found.
     132             :  Output is int32_t in native byte order.
     133             : ****************************************************************************/
     134             : 
     135       10765 : static int fetch_int32_parser(TDB_DATA key, TDB_DATA data, void *private_data)
     136             : {
     137       10765 :         if (data.dsize == sizeof(int32_t)) {
     138       10765 :                 *((int32_t *)private_data) = PULL_LE_I32(data.dptr, 0);
     139             :         }
     140       10765 :         return 0;
     141             : }
     142             : 
     143       11077 : static int32_t tdb_fetch_int32_byblob(struct tdb_context *tdb, TDB_DATA key)
     144             : {
     145       11077 :         int32_t v = -1;
     146       11077 :         int32_t ret = tdb_parse_record(tdb, key, fetch_int32_parser, &v);
     147       11077 :         if (ret == -1) {
     148         312 :                 return ret;
     149             :         }
     150       10765 :         return v;
     151             : }
     152             : 
     153             : /****************************************************************************
     154             :  Fetch a int32_t value by string key, return -1 if not found.
     155             :  Output is int32_t in native byte order.
     156             : ****************************************************************************/
     157             : 
     158       11077 : int32_t tdb_fetch_int32(struct tdb_context *tdb, const char *keystr)
     159             : {
     160       11077 :         return tdb_fetch_int32_byblob(tdb, string_term_tdb_data(keystr));
     161             : }
     162             : 
     163             : /****************************************************************************
     164             :  Store a int32_t value by an arbitrary blob key, return 0 on success, -ve on failure.
     165             :  Input is int32_t in native byte order. Output in tdb is in little-endian.
     166             : ****************************************************************************/
     167             : 
     168        5327 : static int tdb_store_int32_byblob(struct tdb_context *tdb, TDB_DATA key,
     169             :                                   int32_t v)
     170             : {
     171           0 :         TDB_DATA data;
     172           0 :         int32_t v_store;
     173             : 
     174        5327 :         SIVAL(&v_store,0,v);
     175        5327 :         data.dptr = (unsigned char *)&v_store;
     176        5327 :         data.dsize = sizeof(int32_t);
     177             : 
     178        5327 :         return tdb_store(tdb, key, data, TDB_REPLACE);
     179             : }
     180             : 
     181             : /****************************************************************************
     182             :  Store a int32_t value by string key, return 0 on success, -ve on failure.
     183             :  Input is int32_t in native byte order. Output in tdb is in little-endian.
     184             : ****************************************************************************/
     185             : 
     186        5327 : int tdb_store_int32(struct tdb_context *tdb, const char *keystr, int32_t v)
     187             : {
     188        5327 :         return tdb_store_int32_byblob(tdb, string_term_tdb_data(keystr), v);
     189             : }
     190             : 
     191             : /****************************************************************************
     192             :  Fetch a uint32_t value by a arbitrary blob key, return false if not found.
     193             :  Output is uint32_t in native byte order.
     194             : ****************************************************************************/
     195             : 
     196        3762 : static int fetch_uint32_parser(TDB_DATA key, TDB_DATA data, void *private_data)
     197             : {
     198        3762 :         if (data.dsize != sizeof(uint32_t)) {
     199           0 :                 return -1;
     200             :         }
     201        3762 :         *((uint32_t *)private_data) = PULL_LE_U32(data.dptr, 0);
     202        3762 :         return 0;
     203             : }
     204             : 
     205        3895 : static bool tdb_fetch_uint32_byblob(struct tdb_context *tdb, TDB_DATA key,
     206             :                                     uint32_t *value)
     207             : {
     208        3897 :         int ret = tdb_parse_record(tdb, key, fetch_uint32_parser, value);
     209             : 
     210        3895 :         if (ret == -1) {
     211         133 :                 return false;
     212             :         }
     213             : 
     214        3762 :         return true;
     215             : }
     216             : 
     217             : /****************************************************************************
     218             :  Fetch a uint32_t value by string key, return false if not found.
     219             :  Output is uint32_t in native byte order.
     220             : ****************************************************************************/
     221             : 
     222        3895 : bool tdb_fetch_uint32(struct tdb_context *tdb, const char *keystr, uint32_t *value)
     223             : {
     224        3895 :         return tdb_fetch_uint32_byblob(tdb, string_term_tdb_data(keystr), value);
     225             : }
     226             : 
     227             : /****************************************************************************
     228             :  Store a uint32_t value by an arbitrary blob key, return true on success, false on failure.
     229             :  Input is uint32_t in native byte order. Output in tdb is in little-endian.
     230             : ****************************************************************************/
     231             : 
     232        2361 : static bool tdb_store_uint32_byblob(struct tdb_context *tdb, TDB_DATA key,
     233             :                                     uint32_t value)
     234             : {
     235           0 :         TDB_DATA data;
     236           0 :         uint32_t v_store;
     237        2361 :         bool ret = true;
     238             : 
     239        2361 :         SIVAL(&v_store, 0, value);
     240        2361 :         data.dptr = (unsigned char *)&v_store;
     241        2361 :         data.dsize = sizeof(uint32_t);
     242             : 
     243        2361 :         if (tdb_store(tdb, key, data, TDB_REPLACE) != 0)
     244           0 :                 ret = false;
     245             : 
     246        2361 :         return ret;
     247             : }
     248             : 
     249             : /****************************************************************************
     250             :  Store a uint32_t value by string key, return true on success, false on failure.
     251             :  Input is uint32_t in native byte order. Output in tdb is in little-endian.
     252             : ****************************************************************************/
     253             : 
     254        2361 : bool tdb_store_uint32(struct tdb_context *tdb, const char *keystr, uint32_t value)
     255             : {
     256        2361 :         return tdb_store_uint32_byblob(tdb, string_term_tdb_data(keystr), value);
     257             : }
     258             : /****************************************************************************
     259             :  Store a buffer by a null terminated string key.  Return 0 on success, -ve
     260             :  on failure.
     261             : ****************************************************************************/
     262             : 
     263        2608 : int tdb_store_bystring(struct tdb_context *tdb, const char *keystr, TDB_DATA data, int flags)
     264             : {
     265        2608 :         TDB_DATA key = string_term_tdb_data(keystr);
     266             : 
     267        2608 :         return tdb_store(tdb, key, data, flags);
     268             : }
     269             : 
     270             : /****************************************************************************
     271             :  Fetch a buffer using a null terminated string key.  Don't forget to call
     272             :  free() on the result dptr.
     273             : ****************************************************************************/
     274             : 
     275      224837 : TDB_DATA tdb_fetch_bystring(struct tdb_context *tdb, const char *keystr)
     276             : {
     277      224837 :         TDB_DATA key = string_term_tdb_data(keystr);
     278             : 
     279      224837 :         return tdb_fetch(tdb, key);
     280             : }
     281             : 
     282             : /****************************************************************************
     283             :  Delete an entry using a null terminated string key.
     284             : ****************************************************************************/
     285             : 
     286           4 : int tdb_delete_bystring(struct tdb_context *tdb, const char *keystr)
     287             : {
     288           4 :         TDB_DATA key = string_term_tdb_data(keystr);
     289             : 
     290           4 :         return tdb_delete(tdb, key);
     291             : }
     292             : 
     293             : /****************************************************************************
     294             :  Atomic integer change. Returns old value. To create, set initial value in *oldval.
     295             : ****************************************************************************/
     296             : 
     297         988 : int32_t tdb_change_int32_atomic(struct tdb_context *tdb, const char *keystr, int32_t *oldval, int32_t change_val)
     298             : {
     299           0 :         int32_t val;
     300         988 :         int32_t ret = -1;
     301             : 
     302         988 :         if (tdb_lock_bystring(tdb, keystr) != 0)
     303           0 :                 return -1;
     304             : 
     305         988 :         if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
     306             :                 /* The lookup failed */
     307           6 :                 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
     308             :                         /* but not because it didn't exist */
     309           0 :                         goto err_out;
     310             :                 }
     311             : 
     312             :                 /* Start with 'old' value */
     313           6 :                 val = *oldval;
     314             : 
     315             :         } else {
     316             :                 /* It worked, set return value (oldval) to tdb data */
     317         982 :                 *oldval = val;
     318             :         }
     319             : 
     320             :         /* Increment value for storage and return next time */
     321         988 :         val += change_val;
     322             : 
     323         988 :         if (tdb_store_int32(tdb, keystr, val) != 0)
     324           0 :                 goto err_out;
     325             : 
     326         988 :         ret = 0;
     327             : 
     328         988 :   err_out:
     329             : 
     330         988 :         tdb_unlock_bystring(tdb, keystr);
     331         988 :         return ret;
     332             : }
     333             : 
     334             : /****************************************************************************
     335             :  Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
     336             : ****************************************************************************/
     337             : 
     338           0 : bool tdb_change_uint32_atomic(struct tdb_context *tdb, const char *keystr, uint32_t *oldval, uint32_t change_val)
     339             : {
     340           0 :         uint32_t val;
     341           0 :         bool ret = false;
     342             : 
     343           0 :         if (tdb_lock_bystring(tdb, keystr) != 0)
     344           0 :                 return false;
     345             : 
     346           0 :         if (!tdb_fetch_uint32(tdb, keystr, &val)) {
     347             :                 /* It failed */
     348           0 :                 if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
     349             :                         /* and not because it didn't exist */
     350           0 :                         goto err_out;
     351             :                 }
     352             : 
     353             :                 /* Start with 'old' value */
     354           0 :                 val = *oldval;
     355             : 
     356             :         } else {
     357             :                 /* it worked, set return value (oldval) to tdb data */
     358           0 :                 *oldval = val;
     359             : 
     360             :         }
     361             : 
     362             :         /* get a new value to store */
     363           0 :         val += change_val;
     364             : 
     365           0 :         if (!tdb_store_uint32(tdb, keystr, val))
     366           0 :                 goto err_out;
     367             : 
     368           0 :         ret = true;
     369             : 
     370           0 :   err_out:
     371             : 
     372           0 :         tdb_unlock_bystring(tdb, keystr);
     373           0 :         return ret;
     374             : }
     375             : 
     376             : /****************************************************************************
     377             :  Return an NTSTATUS from a TDB_ERROR
     378             : ****************************************************************************/
     379             : 
     380     9106919 : NTSTATUS map_nt_error_from_tdb(enum TDB_ERROR err)
     381             : {
     382       32869 :         NTSTATUS result;
     383             : 
     384     9106919 :         switch (err) {
     385           0 :         case TDB_SUCCESS:
     386           0 :                 result = NT_STATUS_OK;
     387           0 :                 break;
     388           0 :         case TDB_ERR_CORRUPT:
     389           0 :                 result = NT_STATUS_INTERNAL_DB_CORRUPTION;
     390           0 :                 break;
     391           0 :         case TDB_ERR_IO:
     392           0 :                 result = NT_STATUS_UNEXPECTED_IO_ERROR;
     393           0 :                 break;
     394           0 :         case TDB_ERR_OOM:
     395           0 :                 result = NT_STATUS_NO_MEMORY;
     396           0 :                 break;
     397           0 :         case TDB_ERR_EXISTS:
     398           0 :                 result = NT_STATUS_OBJECT_NAME_COLLISION;
     399           0 :                 break;
     400             : 
     401           0 :         case TDB_ERR_LOCK:
     402             :                 /*
     403             :                  * TDB_ERR_LOCK is very broad, we could for example
     404             :                  * distinguish between fcntl locks and invalid lock
     405             :                  * sequences. So NT_STATUS_FILE_LOCK_CONFLICT is a
     406             :                  * compromise.
     407             :                  */
     408           0 :                 result = NT_STATUS_FILE_LOCK_CONFLICT;
     409           0 :                 break;
     410             : 
     411           0 :         case TDB_ERR_NOLOCK:
     412             :         case TDB_ERR_LOCK_TIMEOUT:
     413             :                 /*
     414             :                  * These two ones in the enum are not actually used
     415             :                  */
     416           0 :                 result = NT_STATUS_FILE_LOCK_CONFLICT;
     417           0 :                 break;
     418     9074050 :         case TDB_ERR_NOEXIST:
     419     9074050 :                 result = NT_STATUS_NOT_FOUND;
     420     9074050 :                 break;
     421           0 :         case TDB_ERR_EINVAL:
     422           0 :                 result = NT_STATUS_INVALID_PARAMETER;
     423           0 :                 break;
     424           0 :         case TDB_ERR_RDONLY:
     425           0 :                 result = NT_STATUS_ACCESS_DENIED;
     426           0 :                 break;
     427           0 :         case TDB_ERR_NESTING:
     428           0 :                 result = NT_STATUS_INTERNAL_ERROR;
     429           0 :                 break;
     430           0 :         default:
     431           0 :                 result = NT_STATUS_INTERNAL_ERROR;
     432           0 :                 break;
     433       32869 :         };
     434     9106919 :         return result;
     435             : }
     436             : 
     437     1780712 : int map_unix_error_from_tdb(enum TDB_ERROR err)
     438             : {
     439     1780712 :         int result = EINVAL;
     440             : 
     441     1780712 :         switch (err) {
     442           0 :         case TDB_SUCCESS:
     443           0 :                 result = 0;
     444           0 :                 break;
     445           0 :         case TDB_ERR_CORRUPT:
     446           0 :                 result = EILSEQ;
     447           0 :                 break;
     448           0 :         case TDB_ERR_IO:
     449           0 :                 result = EIO;
     450           0 :                 break;
     451           0 :         case TDB_ERR_OOM:
     452           0 :                 result = ENOMEM;
     453           0 :                 break;
     454           0 :         case TDB_ERR_EXISTS:
     455           0 :                 result = EEXIST;
     456           0 :                 break;
     457             : 
     458           0 :         case TDB_ERR_LOCK:
     459             :                 /*
     460             :                  * TDB_ERR_LOCK is very broad, we could for example
     461             :                  * distinguish between fcntl locks and invalid lock
     462             :                  * sequences. EWOULDBLOCK is wrong, but there is no real
     463             :                  * generic lock error code in errno.h
     464             :                  */
     465           0 :                 result = EWOULDBLOCK;
     466           0 :                 break;
     467             : 
     468           0 :         case TDB_ERR_NOLOCK:
     469             :         case TDB_ERR_LOCK_TIMEOUT:
     470             :                 /*
     471             :                  * These two ones in the enum are not actually used
     472             :                  */
     473           0 :                 result = ENOLCK;
     474           0 :                 break;
     475     1756296 :         case TDB_ERR_NOEXIST:
     476     1756296 :                 result = ENOENT;
     477     1756296 :                 break;
     478           0 :         case TDB_ERR_EINVAL:
     479           0 :                 result = EINVAL;
     480           0 :                 break;
     481           0 :         case TDB_ERR_RDONLY:
     482           0 :                 result = EROFS;
     483           0 :                 break;
     484           0 :         case TDB_ERR_NESTING:
     485             :                 /*
     486             :                  * Well, this db is already busy...
     487             :                  */
     488           0 :                 result = EBUSY;
     489           0 :                 break;
     490       24416 :         };
     491     1780712 :         return result;
     492             : }
     493             : 
     494             : struct tdb_fetch_talloc_state {
     495             :         TALLOC_CTX *mem_ctx;
     496             :         uint8_t *buf;
     497             : };
     498             : 
     499     1887891 : static int tdb_fetch_talloc_parser(TDB_DATA key, TDB_DATA data,
     500             :                                    void *private_data)
     501             : {
     502     1887891 :         struct tdb_fetch_talloc_state *state = private_data;
     503     1887891 :         state->buf = talloc_memdup(state->mem_ctx, data.dptr, data.dsize);
     504     1887891 :         return 0;
     505             : }
     506             : 
     507     3668603 : int tdb_fetch_talloc(struct tdb_context *tdb, TDB_DATA key,
     508             :                      TALLOC_CTX *mem_ctx, uint8_t **buf)
     509             : {
     510     3668603 :         struct tdb_fetch_talloc_state state = { .mem_ctx = mem_ctx };
     511       31997 :         int ret;
     512             : 
     513     3668603 :         ret = tdb_parse_record(tdb, key, tdb_fetch_talloc_parser, &state);
     514     3668603 :         if (ret == -1) {
     515     1780712 :                 enum TDB_ERROR err = tdb_error(tdb);
     516     1780712 :                 return map_unix_error_from_tdb(err);
     517             :         }
     518             : 
     519     1887891 :         if (state.buf == NULL) {
     520           0 :                 return ENOMEM;
     521             :         }
     522             : 
     523     1887891 :         *buf = state.buf;
     524     1887891 :         return 0;
     525             : }

Generated by: LCOV version 1.14