LCOV - code coverage report
Current view: top level - source3/lib - util_tdb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 193 259 74.5 %
Date: 2024-02-28 12:06:22 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    tdb utility functions
       4             :    Copyright (C) Andrew Tridgell   1992-1998
       5             :    Copyright (C) Rafal Szczesniak  2002
       6             :    Copyright (C) Michael Adam      2007
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "system/filesys.h"
      24             : #include "util_tdb.h"
      25             : #include "cbuf.h"
      26             : 
      27             : #undef malloc
      28             : #undef realloc
      29             : #undef calloc
      30             : #undef strdup
      31             : 
      32             : /****************************************************************************
      33             :  Useful pair of routines for packing/unpacking data consisting of
      34             :  integers and strings.
      35             : ****************************************************************************/
      36             : 
      37      626279 : static size_t tdb_pack_va(uint8_t *buf, int bufsize, const char *fmt, va_list ap)
      38             : {
      39         418 :         uint8_t bt;
      40         418 :         uint16_t w;
      41         418 :         uint32_t d;
      42         418 :         int i;
      43         418 :         void *p;
      44      626279 :         int len = 0;
      45         418 :         char *s;
      46         418 :         char c;
      47      626279 :         const char *fmt0 = fmt;
      48      626279 :         int bufsize0 = bufsize;
      49      626279 :         size_t to_write = 0;
      50     5304754 :         while (*fmt) {
      51     4678475 :                 switch ((c = *fmt++)) {
      52           0 :                 case 'b': /* unsigned 8-bit integer */
      53           0 :                         len = 1;
      54           0 :                         bt = (uint8_t)va_arg(ap, int);
      55           0 :                         if (bufsize && bufsize >= len)
      56           0 :                                 SSVAL(buf, 0, bt);
      57           0 :                         break;
      58      315318 :                 case 'w': /* unsigned 16-bit integer */
      59      315318 :                         len = 2;
      60      315318 :                         w = (uint16_t)va_arg(ap, int);
      61      315318 :                         if (bufsize && bufsize >= len)
      62      157659 :                                 SSVAL(buf, 0, w);
      63      315282 :                         break;
      64     1868754 :                 case 'd': /* signed 32-bit integer (standard int in most systems) */
      65     1868754 :                         len = 4;
      66     1868754 :                         d = va_arg(ap, uint32_t);
      67     1868754 :                         if (bufsize && bufsize >= len)
      68      937812 :                                 SIVAL(buf, 0, d);
      69     1868311 :                         break;
      70           0 :                 case 'p': /* pointer */
      71           0 :                         len = 4;
      72           0 :                         p = va_arg(ap, void *);
      73           0 :                         d = p?1:0;
      74           0 :                         if (bufsize && bufsize >= len)
      75           0 :                                 SIVAL(buf, 0, d);
      76           0 :                         break;
      77      513907 :                 case 'P': /* null-terminated string */
      78             :                 case 'f': /* null-terminated string */
      79      513907 :                         s = va_arg(ap,char *);
      80      513907 :                         if (s == NULL) {
      81           0 :                                 smb_panic("Invalid argument");
      82             :                         }
      83      513907 :                         w = strlen(s);
      84      513907 :                         len = w + 1;
      85      513907 :                         if (bufsize && bufsize >= len)
      86      318705 :                                 memcpy(buf, s, len);
      87      513704 :                         break;
      88     1980496 :                 case 'B': /* fixed-length string */
      89     1980496 :                         i = va_arg(ap, int);
      90     1980496 :                         s = va_arg(ap, char *);
      91     1980496 :                         len = 4+i;
      92     1980496 :                         if (bufsize && bufsize >= len) {
      93      990248 :                                 SIVAL(buf, 0, i);
      94      990248 :                                 if (s != NULL) {
      95      682603 :                                         memcpy(buf+4, s, i);
      96             :                                 }
      97             :                         }
      98     1980208 :                         break;
      99           0 :                 default:
     100           0 :                         DEBUG(0,("Unknown tdb_pack format %c in %s\n", 
     101             :                                  c, fmt));
     102           0 :                         len = 0;
     103           0 :                         break;
     104             :                 }
     105             : 
     106     4678475 :                 to_write += len;
     107     4678475 :                 if (bufsize > 0) {
     108     2404704 :                         bufsize -= len;
     109     2404704 :                         buf += len;
     110             :                 }
     111     4678475 :                 if (bufsize < 0)
     112      147426 :                         bufsize = 0;
     113             :         }
     114             : 
     115      626279 :         DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n", 
     116             :                  fmt0, bufsize0, (int)to_write));
     117             : 
     118      626279 :         return to_write;
     119             : }
     120             : 
     121      626279 : size_t tdb_pack(uint8_t *buf, int bufsize, const char *fmt, ...)
     122             : {
     123         418 :         va_list ap;
     124         418 :         size_t result;
     125             : 
     126      626279 :         va_start(ap, fmt);
     127      626279 :         result = tdb_pack_va(buf, bufsize, fmt, ap);
     128      626279 :         va_end(ap);
     129      626279 :         return result;
     130             : }
     131             : 
     132             : /****************************************************************************
     133             :  Useful pair of routines for packing/unpacking data consisting of
     134             :  integers and strings.
     135             : ****************************************************************************/
     136             : 
     137     6632557 : int tdb_unpack(const uint8_t *buf, int in_bufsize, const char *fmt, ...)
     138             : {
     139        2489 :         va_list ap;
     140        2489 :         uint8_t *bt;
     141        2489 :         uint16_t *w;
     142        2489 :         uint32_t *d;
     143     6632557 :         size_t bufsize = in_bufsize;
     144        2489 :         size_t len;
     145        2489 :         uint32_t *i;
     146        2489 :         void **p;
     147        2489 :         char *s, **b, **ps;
     148        2489 :         char c;
     149     6632557 :         const uint8_t *buf0 = buf;
     150     6632557 :         const char *fmt0 = fmt;
     151             : 
     152     6632557 :         va_start(ap, fmt);
     153             : 
     154    28421409 :         while (*fmt) {
     155    21788852 :                 switch ((c=*fmt++)) {
     156           0 :                 case 'b': /* unsigned 8-bit integer */
     157           0 :                         len = 1;
     158           0 :                         bt = va_arg(ap, uint8_t *);
     159           0 :                         if (bufsize < len)
     160           0 :                                 goto no_space;
     161           0 :                         *bt = SVAL(buf, 0);
     162           0 :                         break;
     163      330918 :                 case 'w': /* unsigned 16-bit integer */
     164      330918 :                         len = 2;
     165      330918 :                         w = va_arg(ap, uint16_t *);
     166      330918 :                         if (bufsize < len)
     167           0 :                                 goto no_space;
     168      330918 :                         *w = SVAL(buf, 0);
     169      330918 :                         break;
     170    10066167 :                 case 'd': /* unsigned 32-bit integer (standard int in most systems) */
     171    10066167 :                         len = 4;
     172    10066167 :                         d = va_arg(ap, uint32_t *);
     173    10066167 :                         if (bufsize < len)
     174           0 :                                 goto no_space;
     175    10066167 :                         *d = IVAL(buf, 0);
     176    10066167 :                         break;
     177           0 :                 case 'p': /* pointer */
     178           0 :                         len = 4;
     179           0 :                         p = va_arg(ap, void **);
     180           0 :                         if (bufsize < len)
     181           0 :                                 goto no_space;
     182             :                         /*
     183             :                          * This isn't a real pointer - only a token (1 or 0)
     184             :                          * to mark the fact a pointer is present.
     185             :                          */
     186             : 
     187           0 :                         *p = (void *)(IVAL(buf, 0) ? (void *)1 : NULL);
     188           0 :                         break;
     189        1380 :                 case 'P': /* null-terminated string */
     190             :                         /* Return malloc'ed string. */
     191        1380 :                         ps = va_arg(ap,char **);
     192        1380 :                         len = strnlen((const char *)buf, bufsize) + 1;
     193        1380 :                         if (bufsize < len)
     194           0 :                                 goto no_space;
     195        1380 :                         if (ps != NULL) {
     196        1380 :                                 *ps = SMB_STRDUP((const char *)buf);
     197        1380 :                                 if (*ps == NULL) {
     198           0 :                                         goto no_space;
     199             :                                 }
     200             :                         }
     201        1380 :                         break;
     202     9068514 :                 case 'f': /* null-terminated string */
     203     9068514 :                         s = va_arg(ap,char *);
     204     9068514 :                         len = strnlen((const char *)buf, bufsize) + 1;
     205     9068514 :                         if (bufsize < len || len > sizeof(fstring))
     206           0 :                                 goto no_space;
     207     9068514 :                         if (s != NULL) {
     208     9068514 :                                 memcpy(s, buf, len);
     209             :                         }
     210     9067549 :                         break;
     211     2321873 :                 case 'B': /* fixed-length string */
     212     2321873 :                         i = va_arg(ap, uint32_t *);
     213     2321873 :                         b = va_arg(ap, char **);
     214     2321873 :                         len = 4;
     215     2321873 :                         if (bufsize < len)
     216           0 :                                 goto no_space;
     217     2321873 :                         *i = IVAL(buf, 0);
     218     2321873 :                         if (! *i) {
     219      667549 :                                 *b = NULL;
     220      667549 :                                 break;
     221             :                         }
     222     1654324 :                         len += *i;
     223     1654324 :                         if (len < *i) {
     224           0 :                                 goto no_space;
     225             :                         }
     226     1654324 :                         if (bufsize < len)
     227           0 :                                 goto no_space;
     228     1654324 :                         if (b != NULL) {
     229     1654324 :                                 *b = (char *)SMB_MALLOC(*i);
     230     1654324 :                                 if (! *b)
     231           0 :                                         goto no_space;
     232     1654324 :                                 memcpy(*b, buf+4, *i);
     233             :                         }
     234     1653803 :                         break;
     235           0 :                 default:
     236           0 :                         DEBUG(0,("Unknown tdb_unpack format %c in %s\n",
     237             :                                  c, fmt));
     238             : 
     239           0 :                         len = 0;
     240           0 :                         break;
     241             :                 }
     242             : 
     243    21788852 :                 buf += len;
     244    21788852 :                 bufsize -= len;
     245             :         }
     246             : 
     247     6632557 :         va_end(ap);
     248             : 
     249     6632557 :         DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
     250             :                  fmt0, in_bufsize, (int)PTR_DIFF(buf, buf0)));
     251             : 
     252     6632557 :         return PTR_DIFF(buf, buf0);
     253             : 
     254           0 :  no_space:
     255           0 :         va_end(ap);
     256           0 :         return -1;
     257             : }
     258             : 
     259             : 
     260             : /****************************************************************************
     261             :  Log tdb messages via DEBUG().
     262             : ****************************************************************************/
     263             : 
     264             : static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level,
     265             :                     const char *format, ...) PRINTF_ATTRIBUTE(3,4);
     266             : 
     267          54 : static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
     268             : {
     269           0 :         va_list ap;
     270          54 :         char *ptr = NULL;
     271           0 :         int ret;
     272             : 
     273          54 :         va_start(ap, format);
     274          54 :         ret = vasprintf(&ptr, format, ap);
     275          54 :         va_end(ap);
     276             : 
     277          54 :         if ((ret == -1) || !*ptr)
     278           0 :                 return;
     279             : 
     280          54 :         DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
     281          54 :         SAFE_FREE(ptr);
     282             : }
     283             : 
     284             : /****************************************************************************
     285             :  Like tdb_open() but also setup a logging function that redirects to
     286             :  the samba DEBUG() system.
     287             : ****************************************************************************/
     288             : 
     289        1123 : TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
     290             :                           int open_flags, mode_t mode)
     291             : {
     292           2 :         TDB_CONTEXT *tdb;
     293        1123 :         struct tdb_logging_context log_ctx = { .log_fn = tdb_log };
     294             : 
     295        1123 :         if (!lp_use_mmap())
     296           0 :                 tdb_flags |= TDB_NOMMAP;
     297             : 
     298        1123 :         if ((hash_size == 0) && (name != NULL)) {
     299         159 :                 const char *base = strrchr_m(name, '/');
     300         159 :                 if (base != NULL) {
     301         159 :                         base += 1;
     302             :                 }
     303             :                 else {
     304           0 :                         base = name;
     305             :                 }
     306         159 :                 hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
     307             :         }
     308             : 
     309        1123 :         tdb = tdb_open_ex(name, hash_size, tdb_flags,
     310             :                           open_flags, mode, &log_ctx, NULL);
     311        1123 :         if (!tdb)
     312          56 :                 return NULL;
     313             : 
     314        1065 :         return tdb;
     315             : }
     316             : 
     317     4283131 : int tdb_data_cmp(TDB_DATA t1, TDB_DATA t2)
     318             : {
     319        9505 :         int ret;
     320     4283131 :         if (t1.dptr == NULL && t2.dptr != NULL) {
     321           0 :                 return -1;
     322             :         }
     323     4283131 :         if (t1.dptr != NULL && t2.dptr == NULL) {
     324           0 :                 return 1;
     325             :         }
     326     4283131 :         if (t1.dptr == t2.dptr) {
     327     1002389 :                 return t1.dsize - t2.dsize;
     328             :         }
     329     3280742 :         ret = memcmp(t1.dptr, t2.dptr, MIN(t1.dsize, t2.dsize));
     330     3280742 :         if (ret == 0) {
     331     3280742 :                 return t1.dsize - t2.dsize;
     332             :         }
     333           0 :         return ret;
     334             : }
     335             : 
     336           8 : char *tdb_data_string(TALLOC_CTX *mem_ctx, TDB_DATA d)
     337             : {
     338           0 :         int len;
     339           8 :         char *ret = NULL;
     340           8 :         cbuf *ost = cbuf_new(mem_ctx);
     341             : 
     342           8 :         if (ost == NULL) {
     343           0 :                 return NULL;
     344             :         }
     345             : 
     346           8 :         len = cbuf_printf(ost, "%zu:", d.dsize);
     347           8 :         if (len == -1) {
     348           0 :                 goto done;
     349             :         }
     350             : 
     351           8 :         if (d.dptr == NULL) {
     352           0 :                 len = cbuf_puts(ost, "<NULL>", -1);
     353             :         } else {
     354           8 :                 len = cbuf_print_quoted(ost, (const char*)d.dptr, d.dsize);
     355             :         }
     356           8 :         if (len == -1) {
     357           0 :                 goto done;
     358             :         }
     359             : 
     360           8 :         cbuf_swapptr(ost, &ret, 0);
     361           8 :         talloc_steal(mem_ctx, ret);
     362             : 
     363           8 : done:
     364           8 :         talloc_free(ost);
     365           8 :         return ret;
     366             : }
     367             : 
     368          14 : char *tdb_data_dbg(TDB_DATA d)
     369             : {
     370          14 :         return hex_encode_talloc(talloc_tos(), d.dptr, d.dsize);
     371             : }
     372             : 
     373             : static sig_atomic_t gotalarm;
     374             : 
     375             : /***************************************************************
     376             :  Signal function to tell us we timed out.
     377             : ****************************************************************/
     378             : 
     379           0 : static void gotalarm_sig(int signum)
     380             : {
     381           0 :         gotalarm = 1;
     382           0 : }
     383             : 
     384             : /****************************************************************************
     385             :  Lock a chain with timeout (in seconds).
     386             : ****************************************************************************/
     387             : 
     388       28075 : static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type)
     389             : {
     390             :         /* Allow tdb_chainlock to be interrupted by an alarm. */
     391           2 :         int ret;
     392       28075 :         gotalarm = 0;
     393             : 
     394       28075 :         if (timeout) {
     395       28075 :                 CatchSignal(SIGALRM, gotalarm_sig);
     396       28075 :                 tdb_setalarm_sigptr(tdb, &gotalarm);
     397       28075 :                 alarm(timeout);
     398             :         }
     399             : 
     400       28075 :         if (rw_type == F_RDLCK)
     401         236 :                 ret = tdb_chainlock_read(tdb, key);
     402             :         else
     403       27839 :                 ret = tdb_chainlock(tdb, key);
     404             : 
     405       28075 :         if (timeout) {
     406       28075 :                 alarm(0);
     407       28075 :                 tdb_setalarm_sigptr(tdb, NULL);
     408       28075 :                 CatchSignal(SIGALRM, SIG_IGN);
     409       28075 :                 if (gotalarm && (ret != 0)) {
     410           0 :                         DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
     411             :                                 timeout, key.dptr, tdb_name(tdb)));
     412             :                         /* TODO: If we time out waiting for a lock, it might
     413             :                          * be nice to use F_GETLK to get the pid of the
     414             :                          * process currently holding the lock and print that
     415             :                          * as part of the debugging message. -- mbp */
     416           0 :                         return -1;
     417             :                 }
     418             :         }
     419             : 
     420       28075 :         return ret == 0 ? 0 : -1;
     421             : }
     422             : 
     423             : /****************************************************************************
     424             :  Write lock a chain. Return non-zero if timeout or lock failed.
     425             : ****************************************************************************/
     426             : 
     427       27839 : int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
     428             : {
     429       27839 :         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
     430             : }
     431             : 
     432       26492 : int tdb_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
     433             :                                    int timeout)
     434             : {
     435       26492 :         TDB_DATA key = string_term_tdb_data(keyval);
     436             : 
     437       26492 :         return tdb_chainlock_with_timeout(tdb, key, timeout);
     438             : }
     439             : 
     440             : /****************************************************************************
     441             :  Read lock a chain by string. Return non-zero if timeout or lock failed.
     442             : ****************************************************************************/
     443             : 
     444         236 : int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
     445             : {
     446         236 :         TDB_DATA key = string_term_tdb_data(keyval);
     447             : 
     448         236 :         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
     449             : }

Generated by: LCOV version 1.14