LCOV - code coverage report
Current view: top level - source3/lib - util_tdb.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 143 233 61.4 %
Date: 2024-06-13 04:01:37 Functions: 9 12 75.0 %

          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       22907 : static size_t tdb_pack_va(uint8_t *buf, int bufsize, const char *fmt, va_list ap)
      38             : {
      39             :         uint8_t bt;
      40             :         uint16_t w;
      41             :         uint32_t d;
      42             :         int i;
      43             :         void *p;
      44       22907 :         int len = 0;
      45             :         char *s;
      46             :         char c;
      47       22907 :         const char *fmt0 = fmt;
      48       22907 :         int bufsize0 = bufsize;
      49       22907 :         size_t to_write = 0;
      50      213905 :         while (*fmt) {
      51      173351 :                 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       12750 :                 case 'w': /* unsigned 16-bit integer */
      59       12750 :                         len = 2;
      60       12750 :                         w = (uint16_t)va_arg(ap, int);
      61       12750 :                         if (bufsize && bufsize >= len)
      62        6375 :                                 SSVAL(buf, 0, w);
      63       12750 :                         break;
      64       70723 :                 case 'd': /* signed 32-bit integer (standard int in most systems) */
      65       70723 :                         len = 4;
      66       70723 :                         d = va_arg(ap, uint32_t);
      67       70723 :                         if (bufsize && bufsize >= len)
      68       37686 :                                 SIVAL(buf, 0, d);
      69       70723 :                         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       16556 :                 case 'P': /* null-terminated string */
      78             :                 case 'f': /* null-terminated string */
      79       16556 :                         s = va_arg(ap,char *);
      80       16556 :                         if (s == NULL) {
      81           0 :                                 smb_panic("Invalid argument");
      82             :                         }
      83       16556 :                         w = strlen(s);
      84       16556 :                         len = w + 1;
      85       16556 :                         if (bufsize && bufsize >= len)
      86       10176 :                                 memcpy(buf, s, len);
      87       16556 :                         break;
      88       73322 :                 case 'B': /* fixed-length string */
      89       73322 :                         i = va_arg(ap, int);
      90       73322 :                         s = va_arg(ap, char *);
      91       73322 :                         len = 4+i;
      92       73322 :                         if (bufsize && bufsize >= len) {
      93       36661 :                                 SIVAL(buf, 0, i);
      94       36661 :                                 if (s != NULL) {
      95       23463 :                                         memcpy(buf+4, s, i);
      96             :                                 }
      97             :                         }
      98       73322 :                         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      173351 :                 to_write += len;
     107      173351 :                 if (bufsize > 0) {
     108       90898 :                         bufsize -= len;
     109       90898 :                         buf += len;
     110             :                 }
     111      173351 :                 if (bufsize < 0)
     112        2661 :                         bufsize = 0;
     113             :         }
     114             : 
     115       22907 :         DEBUG(18,("tdb_pack_va(%s, %d) -> %d\n", 
     116             :                  fmt0, bufsize0, (int)to_write));
     117             : 
     118       22907 :         return to_write;
     119             : }
     120             : 
     121       22907 : size_t tdb_pack(uint8_t *buf, int bufsize, const char *fmt, ...)
     122             : {
     123             :         va_list ap;
     124             :         size_t result;
     125             : 
     126       22907 :         va_start(ap, fmt);
     127       22907 :         result = tdb_pack_va(buf, bufsize, fmt, ap);
     128       22907 :         va_end(ap);
     129       22907 :         return result;
     130             : }
     131             : 
     132             : /****************************************************************************
     133             :  Useful pair of routines for packing/unpacking data consisting of
     134             :  integers and strings.
     135             : ****************************************************************************/
     136             : 
     137       68713 : int tdb_unpack(const uint8_t *buf, int in_bufsize, const char *fmt, ...)
     138             : {
     139             :         va_list ap;
     140             :         uint8_t *bt;
     141             :         uint16_t *w;
     142             :         uint32_t *d;
     143       68713 :         size_t bufsize = in_bufsize;
     144             :         size_t len;
     145             :         uint32_t *i;
     146             :         void **p;
     147             :         char *s, **b, **ps;
     148             :         char c;
     149       68713 :         const uint8_t *buf0 = buf;
     150       68713 :         const char *fmt0 = fmt;
     151             : 
     152       68713 :         va_start(ap, fmt);
     153             : 
     154      337893 :         while (*fmt) {
     155      215181 :                 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        9831 :                 case 'w': /* unsigned 16-bit integer */
     164        9831 :                         len = 2;
     165        9831 :                         w = va_arg(ap, uint16_t *);
     166        9831 :                         if (bufsize < len)
     167           0 :                                 goto no_space;
     168        9831 :                         *w = SVAL(buf, 0);
     169        9831 :                         break;
     170      106518 :                 case 'd': /* unsigned 32-bit integer (standard int in most systems) */
     171      106518 :                         len = 4;
     172      106518 :                         d = va_arg(ap, uint32_t *);
     173      106518 :                         if (bufsize < len)
     174           0 :                                 goto no_space;
     175      106518 :                         *d = IVAL(buf, 0);
     176      106518 :                         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           0 :                 case 'P': /* null-terminated string */
     190             :                         /* Return malloc'ed string. */
     191           0 :                         ps = va_arg(ap,char **);
     192           0 :                         len = strnlen((const char *)buf, bufsize) + 1;
     193           0 :                         if (bufsize < len)
     194           0 :                                 goto no_space;
     195           0 :                         if (ps != NULL) {
     196           0 :                                 *ps = SMB_STRDUP((const char *)buf);
     197           0 :                                 if (*ps == NULL) {
     198           0 :                                         goto no_space;
     199             :                                 }
     200             :                         }
     201           0 :                         break;
     202       45193 :                 case 'f': /* null-terminated string */
     203       45193 :                         s = va_arg(ap,char *);
     204       45193 :                         len = strnlen((const char *)buf, bufsize) + 1;
     205       45193 :                         if (bufsize < len || len > sizeof(fstring))
     206           0 :                                 goto no_space;
     207       45193 :                         if (s != NULL) {
     208       45193 :                                 memcpy(s, buf, len);
     209             :                         }
     210       45193 :                         break;
     211       53639 :                 case 'B': /* fixed-length string */
     212       53639 :                         i = va_arg(ap, uint32_t *);
     213       53639 :                         b = va_arg(ap, char **);
     214       53639 :                         len = 4;
     215       53639 :                         if (bufsize < len)
     216           0 :                                 goto no_space;
     217       53639 :                         *i = IVAL(buf, 0);
     218       53639 :                         if (! *i) {
     219       20345 :                                 *b = NULL;
     220       20345 :                                 break;
     221             :                         }
     222       33294 :                         len += *i;
     223       33294 :                         if (len < *i) {
     224           0 :                                 goto no_space;
     225             :                         }
     226       33294 :                         if (bufsize < len)
     227           0 :                                 goto no_space;
     228       33294 :                         if (b != NULL) {
     229       33294 :                                 *b = (char *)SMB_MALLOC(*i);
     230       33294 :                                 if (! *b)
     231           0 :                                         goto no_space;
     232       33294 :                                 memcpy(*b, buf+4, *i);
     233             :                         }
     234       33294 :                         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      215181 :                 buf += len;
     244      215181 :                 bufsize -= len;
     245             :         }
     246             : 
     247       68713 :         va_end(ap);
     248             : 
     249       68713 :         DEBUG(18,("tdb_unpack(%s, %d) -> %d\n",
     250             :                  fmt0, in_bufsize, (int)PTR_DIFF(buf, buf0)));
     251             : 
     252       68713 :         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          29 : static void tdb_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, const char *format, ...)
     268             : {
     269             :         va_list ap;
     270          29 :         char *ptr = NULL;
     271             :         int ret;
     272             : 
     273          29 :         va_start(ap, format);
     274          29 :         ret = vasprintf(&ptr, format, ap);
     275          29 :         va_end(ap);
     276             : 
     277          29 :         if ((ret == -1) || !*ptr)
     278           0 :                 return;
     279             : 
     280          29 :         DEBUG((int)level, ("tdb(%s): %s", tdb_name(tdb) ? tdb_name(tdb) : "unnamed", ptr));
     281          29 :         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         385 : TDB_CONTEXT *tdb_open_log(const char *name, int hash_size, int tdb_flags,
     290             :                           int open_flags, mode_t mode)
     291             : {
     292             :         TDB_CONTEXT *tdb;
     293         385 :         struct tdb_logging_context log_ctx = { .log_fn = tdb_log };
     294             : 
     295         385 :         if (!lp_use_mmap())
     296           0 :                 tdb_flags |= TDB_NOMMAP;
     297             : 
     298         385 :         if ((hash_size == 0) && (name != NULL)) {
     299         139 :                 const char *base = strrchr_m(name, '/');
     300         139 :                 if (base != NULL) {
     301         139 :                         base += 1;
     302             :                 }
     303             :                 else {
     304           0 :                         base = name;
     305             :                 }
     306         139 :                 hash_size = lp_parm_int(-1, "tdb_hashsize", base, 0);
     307             :         }
     308             : 
     309         385 :         tdb = tdb_open_ex(name, hash_size, tdb_flags,
     310             :                           open_flags, mode, &log_ctx, NULL);
     311         385 :         if (!tdb)
     312          29 :                 return NULL;
     313             : 
     314         356 :         return tdb;
     315             : }
     316             : 
     317       25412 : int tdb_data_cmp(TDB_DATA t1, TDB_DATA t2)
     318             : {
     319             :         int ret;
     320       25412 :         if (t1.dptr == NULL && t2.dptr != NULL) {
     321           0 :                 return -1;
     322             :         }
     323       25412 :         if (t1.dptr != NULL && t2.dptr == NULL) {
     324           0 :                 return 1;
     325             :         }
     326       25412 :         if (t1.dptr == t2.dptr) {
     327           0 :                 return t1.dsize - t2.dsize;
     328             :         }
     329       25412 :         ret = memcmp(t1.dptr, t2.dptr, MIN(t1.dsize, t2.dsize));
     330       25412 :         if (ret == 0) {
     331       25412 :                 return t1.dsize - t2.dsize;
     332             :         }
     333           0 :         return ret;
     334             : }
     335             : 
     336           0 : char *tdb_data_string(TALLOC_CTX *mem_ctx, TDB_DATA d)
     337             : {
     338             :         int len;
     339           0 :         char *ret = NULL;
     340           0 :         cbuf *ost = cbuf_new(mem_ctx);
     341             : 
     342           0 :         if (ost == NULL) {
     343           0 :                 return NULL;
     344             :         }
     345             : 
     346           0 :         len = cbuf_printf(ost, "%zu:", d.dsize);
     347           0 :         if (len == -1) {
     348           0 :                 goto done;
     349             :         }
     350             : 
     351           0 :         if (d.dptr == NULL) {
     352           0 :                 len = cbuf_puts(ost, "<NULL>", -1);
     353             :         } else {
     354           0 :                 len = cbuf_print_quoted(ost, (const char*)d.dptr, d.dsize);
     355             :         }
     356           0 :         if (len == -1) {
     357           0 :                 goto done;
     358             :         }
     359             : 
     360           0 :         cbuf_swapptr(ost, &ret, 0);
     361           0 :         talloc_steal(mem_ctx, ret);
     362             : 
     363           0 : done:
     364           0 :         talloc_free(ost);
     365           0 :         return ret;
     366             : }
     367             : 
     368             : static sig_atomic_t gotalarm;
     369             : 
     370             : /***************************************************************
     371             :  Signal function to tell us we timed out.
     372             : ****************************************************************/
     373             : 
     374           0 : static void gotalarm_sig(int signum)
     375             : {
     376           0 :         gotalarm = 1;
     377           0 : }
     378             : 
     379             : /****************************************************************************
     380             :  Lock a chain with timeout (in seconds).
     381             : ****************************************************************************/
     382             : 
     383         551 : static int tdb_chainlock_with_timeout_internal( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout, int rw_type)
     384             : {
     385             :         /* Allow tdb_chainlock to be interrupted by an alarm. */
     386             :         int ret;
     387         551 :         gotalarm = 0;
     388             : 
     389         551 :         if (timeout) {
     390         551 :                 CatchSignal(SIGALRM, gotalarm_sig);
     391         551 :                 tdb_setalarm_sigptr(tdb, &gotalarm);
     392         551 :                 alarm(timeout);
     393             :         }
     394             : 
     395         551 :         if (rw_type == F_RDLCK)
     396           0 :                 ret = tdb_chainlock_read(tdb, key);
     397             :         else
     398         551 :                 ret = tdb_chainlock(tdb, key);
     399             : 
     400         551 :         if (timeout) {
     401         551 :                 alarm(0);
     402         551 :                 tdb_setalarm_sigptr(tdb, NULL);
     403         551 :                 CatchSignal(SIGALRM, SIG_IGN);
     404         551 :                 if (gotalarm && (ret != 0)) {
     405           0 :                         DEBUG(0,("tdb_chainlock_with_timeout_internal: alarm (%u) timed out for key %s in tdb %s\n",
     406             :                                 timeout, key.dptr, tdb_name(tdb)));
     407             :                         /* TODO: If we time out waiting for a lock, it might
     408             :                          * be nice to use F_GETLK to get the pid of the
     409             :                          * process currently holding the lock and print that
     410             :                          * as part of the debugging message. -- mbp */
     411           0 :                         return -1;
     412             :                 }
     413             :         }
     414             : 
     415         551 :         return ret == 0 ? 0 : -1;
     416             : }
     417             : 
     418             : /****************************************************************************
     419             :  Write lock a chain. Return non-zero if timeout or lock failed.
     420             : ****************************************************************************/
     421             : 
     422         551 : int tdb_chainlock_with_timeout( TDB_CONTEXT *tdb, TDB_DATA key, unsigned int timeout)
     423             : {
     424         551 :         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_WRLCK);
     425             : }
     426             : 
     427         551 : int tdb_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval,
     428             :                                    int timeout)
     429             : {
     430         551 :         TDB_DATA key = string_term_tdb_data(keyval);
     431             : 
     432         551 :         return tdb_chainlock_with_timeout(tdb, key, timeout);
     433             : }
     434             : 
     435             : /****************************************************************************
     436             :  Read lock a chain by string. Return non-zero if timeout or lock failed.
     437             : ****************************************************************************/
     438             : 
     439           0 : int tdb_read_lock_bystring_with_timeout(TDB_CONTEXT *tdb, const char *keyval, unsigned int timeout)
     440             : {
     441           0 :         TDB_DATA key = string_term_tdb_data(keyval);
     442             : 
     443           0 :         return tdb_chainlock_with_timeout_internal(tdb, key, timeout, F_RDLCK);
     444             : }

Generated by: LCOV version 1.13