LCOV - code coverage report
Current view: top level - src/libs/elektra - keyvalue.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 86 86 100.0 %
Date: 2019-09-12 12:28:41 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Methods for Key value manipulation.
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : 
      10             : #ifdef HAVE_KDBCONFIG_H
      11             : #include "kdbconfig.h"
      12             : #endif
      13             : 
      14             : #ifdef HAVE_STDARG_H
      15             : #include <stdarg.h>
      16             : #endif
      17             : 
      18             : #ifdef HAVE_STRING_H
      19             : #include <string.h>
      20             : #endif
      21             : 
      22             : #ifdef HAVE_STDLIB_H
      23             : #include <stdlib.h>
      24             : #endif
      25             : 
      26             : #if DEBUG && defined(HAVE_STDIO_H)
      27             : #include <stdio.h>
      28             : #endif
      29             : 
      30             : #include "kdbprivate.h"
      31             : 
      32             : 
      33             : /**
      34             :  * @defgroup keyvalue Value Manipulation Methods
      35             :  * @ingroup key
      36             :  * @brief Methods to do various operations on Key values.
      37             :  *
      38             :  * A key can contain a value in different format. The most
      39             :  * likely situation is, that the value is interpreted as
      40             :  * text. Use keyGetString() for that.
      41             :  * You can save any Unicode Symbols and Elektra will
      42             :  * take care that you get the same back, independent of
      43             :  * your current environment.
      44             :  *
      45             :  * In some situations this idea fails. When you need exactly
      46             :  * the same value back without any interpretation of the
      47             :  * characters, there is keySetBinary(). If you use that, its
      48             :  * very likely that your Configuration is not according
      49             :  * to the standard. Also for Numbers, Booleans and Date you
      50             :  * should use keyGetString(). To do so, you might use strtod()
      51             :  * strtol() and then atol() or atof() to convert back.
      52             :  *
      53             :  * To use them:
      54             :  * @code
      55             : #include <kdb.h>
      56             :  * @endcode
      57             :  *
      58             :  *
      59             :  */
      60             : 
      61             : 
      62             : /*******************************************
      63             :  *    General value manipulation methods   *
      64             :  *******************************************/
      65             : 
      66             : 
      67             : /**
      68             :  * Return a pointer to the real internal @p key value.
      69             :  *
      70             :  * This is a much more efficient version of keyGetString()
      71             :  * keyGetBinary(), and you should use it if you are responsible enough to
      72             :  * not mess up things. You are not allowed to modify anything
      73             :  * in the returned string. If you need a copy of the Value, consider
      74             :  * to use keyGetString() or keyGetBinary() instead.
      75             :  *
      76             :  * @section string String Handling
      77             :  *
      78             :  * If @p key is string (keyIsString()), you may cast the returned as a
      79             :  * @c "char *" because you'll get a NULL terminated regular string.
      80             :  *
      81             :  * keyValue() returns "" in string mode when there is no value. The reason is
      82             :  * @code
      83             : key=keyNew(0);
      84             : keySetString(key,"");
      85             : keyValue(key); // you would expect "" here
      86             : keyDel(key);
      87             :  * @endcode
      88             :  *
      89             :  * @section binary Binary Data Handling
      90             :  *
      91             :  * If the data is binary, the size of the value must be determined by
      92             :  * keyGetValueSize(), any strlen() operations are not suitable to determine
      93             :  * the size.
      94             :  *
      95             :  * keyValue() returns 0 in binary mode when there is no value. The reason is
      96             :  * @code
      97             : key=keyNew(0);
      98             : keySetBinary(key, 0, 0);
      99             : keyValue(key); // you would expect 0 here
     100             : 
     101             : keySetBinary(key,"", 1);
     102             : keyValue(key); // you would expect "" (a pointer to '\0') here
     103             : 
     104             : int i=23;
     105             : keySetBinary(key, (void*)&i, 4);
     106             : (int*)keyValue(key); // you would expect a pointer to (int)23 here
     107             : keyDel(key);
     108             :  * @endcode
     109             :  *
     110             :  * @note Note that the Key structure keeps its own size field that is calculated
     111             :  * by library internal calls, so to avoid inconsistencies, you
     112             :  * must never use the pointer returned by keyValue() method to set a new
     113             :  * value. Use keySetString() or keySetBinary() instead.
     114             :  *
     115             :  * @warning Binary keys will return a NULL pointer when there is no data in contrast
     116             :  * to keyName(), keyBaseName(), keyOwner() and keyComment(). For string value the
     117             :  * behaviour is the same.
     118             :  *
     119             :  * @par Example:
     120             :  * @code
     121             : KDB *handle = kdbOpen();
     122             : KeySet *ks=ksNew(0, KS_END);
     123             : Key *current=0;
     124             : 
     125             : kdbGetByName(handle,ks,"system/sw/my",KDB_O_SORT|KDB_O_RECURSIVE);
     126             : 
     127             : ksRewind(ks);
     128             : while (current=ksNext(ks)) {
     129             :         size_t size=0;
     130             : 
     131             :         if (keyIsBin(current)) {
     132             :                 size=keyGetValueSize(current);
     133             :                 printf("Key %s has a value of size %d bytes. Value: <BINARY>\nComment: %s",
     134             :                         keyName(current),
     135             :                         size,
     136             :                         keyComment(current));
     137             :         } else {
     138             :                 size=elektraStrLen((char *)keyValue(current));
     139             :                 printf("Key %s has a value of size %d bytes. Value: %s\nComment: %s",
     140             :                         keyName(current),
     141             :                         size,
     142             :                         (char *)keyValue(current),
     143             :                         keyComment(current));
     144             :         }
     145             : }
     146             : 
     147             : ksDel (ks);
     148             : kdbClose (handle);
     149             :  * @endcode
     150             :  *
     151             :  * @param key the key object to work with
     152             :  * @return a pointer to internal value
     153             :  * @retval "" when there is no data and key is not binary
     154             :  * @retval 0 where there is no data and key is binary
     155             :  * @retval 0 on NULL pointer
     156             :  * @see keyGetValueSize(), keyGetString(), keyGetBinary()
     157             :  * @ingroup keyvalue
     158             :  */
     159     2036943 : const void * keyValue (const Key * key)
     160             : {
     161     2036943 :         if (!key) return 0;
     162             : 
     163      648382 :         if (!key->data.v)
     164             :         {
     165             :                 /*errno=KDB_ERR_NOKEY;*/
     166        2535 :                 if (keyIsBinary (key))
     167             :                         return 0;
     168             :                 else
     169        2437 :                         return "";
     170             :         }
     171             : 
     172             :         return key->data.v;
     173             : }
     174             : 
     175             : 
     176             : /**
     177             :  * Get the c-string representing the value.
     178             :  *
     179             :  * Will return (null) on null pointers.
     180             :  * Will return (binary) on binary data not ended
     181             :  * with a null byte.
     182             :  *
     183             :  * It is not checked if it is actually a string,
     184             :  * only if it terminates for security reasons.
     185             :  *
     186             :  * @return the c-string of the value
     187             :  * @retval "(null)" on null keys
     188             :  * @retval "" if no data found
     189             :  * @retval "(binary)" on binary keys
     190             :  * @ingroup keyvalue
     191             :  * @param key the key object to get the string from
     192             :  */
     193     1512450 : const char * keyString (const Key * key)
     194             : {
     195     1512450 :         if (!key) return "(null)";
     196             : 
     197     1495785 :         if (!key->data.c)
     198             :         {
     199             :                 return "";
     200             :         }
     201             : 
     202     1437598 :         if (keyIsBinary (key))
     203             :         {
     204             :                 return "(binary)";
     205             :         }
     206             : 
     207     1437574 :         return key->data.c;
     208             : }
     209             : 
     210             : 
     211             : /**
     212             :  * Returns the number of bytes needed to store the key value, including the
     213             :  * NULL terminator.
     214             :  *
     215             :  * It returns the correct size, independent of the Key Type.
     216             :  * If it is a binary there might be '\\0' values in it.
     217             :  *
     218             :  * For an empty string you need one byte to store the ending NULL.
     219             :  * For that reason 1 is returned. This is not true for binary data,
     220             :  * so there might be returned 0 too.
     221             :  *
     222             :  * A binary key has no '\\0' termination. String types have it, so to there
     223             :  * length will be added 1 to have enough space to store it.
     224             :  *
     225             :  * This method can be used with elektraMalloc() before keyGetString() or keyGetBinary()
     226             :  * is called.
     227             :  *
     228             :  * @code
     229             : char *buffer;
     230             : buffer = elektraMalloc (keyGetValueSize (key));
     231             : // use this buffer to store the value (binary or string)
     232             : // pass keyGetValueSize (key) for maxSize
     233             :  * @endcode
     234             :  *
     235             :  * @param key the key object to work with
     236             :  * @return the number of bytes needed to store the key value
     237             :  * @retval 1 when there is no data and type is not binary
     238             :  * @retval 0 when there is no data and type is binary
     239             :  * @retval -1 on null pointer
     240             :  * @see keyGetString(), keyGetBinary(), keyValue()
     241             :  * @ingroup keyvalue
     242             :  */
     243     2163898 : ssize_t keyGetValueSize (const Key * key)
     244             : {
     245     2163898 :         if (!key) return -1;
     246             : 
     247     2163738 :         if (!key->data.v)
     248             :         {
     249             :                 /*errno=KDB_ERR_NODATA;*/
     250       37705 :                 if (keyIsBinary (key))
     251             :                         return 0;
     252             :                 else
     253       37355 :                         return 1;
     254             :         }
     255             : 
     256     2126033 :         return key->dataSize;
     257             : }
     258             : 
     259             : 
     260             : /**
     261             :  * Get the value of a key as a string.
     262             :  *
     263             :  * When there is no value inside the string, 1 will
     264             :  * be returned and the returnedString will be empty
     265             :  * "" to avoid programming errors that old strings are
     266             :  * shown to the user.
     267             :  *
     268             :  * For binary values see keyGetBinary() and keyIsBinary().
     269             :  *
     270             :  * @par Example:
     271             :  * @code
     272             : Key *key = keyNew ("user/keyname", KEY_END);
     273             : char buffer[300];
     274             : 
     275             : if (keyGetString(key,buffer,sizeof(buffer)) == -1)
     276             : {
     277             :         // handle error
     278             : } else {
     279             :         printf ("buffer: %s\n", buffer);
     280             : }
     281             :  * @endcode
     282             :  *
     283             :  * @param key the object to gather the value from
     284             :  * @param returnedString pre-allocated memory to store a copy of the key value
     285             :  * @param maxSize number of bytes of allocated memory in @p returnedString
     286             :  * @return the number of bytes actually copied to @p returnedString, including
     287             :  *      final NULL
     288             :  * @retval 1 if the string is empty
     289             :  * @retval -1 on any NULL pointers
     290             :  * @retval -1 on type mismatch: string expected, but found binary
     291             :  * @retval -1 maxSize is 0
     292             :  * @retval -1 if maxSize is too small for string
     293             :  * @retval -1 if maxSize is larger than SSIZE_MAX
     294             :  * @see keyValue(), keyGetValueSize(), keySetString(), keyString()
     295             :  * @see keyGetBinary() for working with binary data
     296             :  * @ingroup keyvalue
     297             :  */
     298      250365 : ssize_t keyGetString (const Key * key, char * returnedString, size_t maxSize)
     299             : {
     300      250365 :         if (!key) return -1;
     301             : 
     302      250363 :         if (!maxSize) return -1;
     303      250359 :         if (!returnedString) return -1;
     304      250357 :         if (maxSize > SSIZE_MAX) return -1;
     305             : 
     306      250355 :         if (!keyIsString (key))
     307             :         {
     308             :                 /*errno=KDB_ERR_TYPEMISMATCH;*/
     309             :                 return -1;
     310             :         }
     311             : 
     312      250332 :         if (!key->data.v)
     313             :         {
     314       32608 :                 returnedString[0] = 0;
     315       32608 :                 return 1;
     316             :         }
     317             : 
     318      217724 :         if (key->dataSize > maxSize)
     319             :         {
     320             :                 /*errno=KDB_ERR_TRUNC;*/
     321             :                 return -1;
     322             :         }
     323             : 
     324             : 
     325      217702 :         strncpy (returnedString, key->data.c, maxSize);
     326      217702 :         return key->dataSize;
     327             : }
     328             : 
     329             : 
     330             : /**
     331             :  * Set the value for @p key as @p newStringValue.
     332             :  *
     333             :  * The function will allocate and save a private copy of @p newStringValue, so
     334             :  * the parameter can be freed after the call.
     335             :  *
     336             :  * String values will be saved in backend storage, when kdbSetKey() will be
     337             :  * called, in UTF-8 universal encoding, regardless of the program's current
     338             :  * encoding, when iconv plugin is present.
     339             :  *
     340             :  * @note The type will be set to KEY_TYPE_STRING.
     341             :  * When the type of the key is already a string type it won't be changed.
     342             :  *
     343             :  * @param key the key to set the string value
     344             :  * @param newStringValue NULL-terminated text string to be set as @p key's
     345             :  *      value
     346             :  * @return the number of bytes actually saved in private struct including final
     347             :  *      NULL
     348             :  * @retval 1 if newStringValue is a NULL pointer, this will make the
     349             :  *           string empty (string only containing null termination)
     350             :  * @retval -1 if key is a NULL pointer
     351             :  * @see keyGetString(), keyValue(), keyString()
     352             :  * @ingroup keyvalue
     353             :  */
     354     1478559 : ssize_t keySetString (Key * key, const char * newStringValue)
     355             : {
     356     1478559 :         ssize_t ret = 0;
     357             : 
     358     1478559 :         if (!key) return -1;
     359             : 
     360     1478494 :         keySetMeta (key, "binary", 0);
     361             : 
     362     1478494 :         if (!newStringValue || newStringValue[0] == '\0')
     363      278583 :                 ret = keySetRaw (key, 0, 0);
     364             :         else
     365     1199911 :                 ret = keySetRaw (key, newStringValue, elektraStrLen (newStringValue));
     366             : 
     367     1478494 :         keySetMeta (key, "origvalue", 0);
     368             : 
     369     1478494 :         return ret;
     370             : }
     371             : 
     372             : 
     373             : /**
     374             :  * Get the value of a key as a binary.
     375             :  *
     376             :  * If the type is not binary -1 will be returned.
     377             :  *
     378             :  * When the binary data is empty (this is not the same as ""!)
     379             :  * 0 will be returned and the returnedBinary will not be changed.
     380             :  *
     381             :  * For string values see keyGetString() and keyIsString().
     382             :  *
     383             :  * When the returnedBinary is to small to hold the data
     384             :  * (its maximum size is given by maxSize),
     385             :  * the returnedBinary will not be changed and -1 is returned.
     386             :  *
     387             :  * @par Example:
     388             :  * @code
     389             : Key *key = keyNew ("user/keyname", KEY_TYPE, KEY_TYPE_BINARY, KEY_END);
     390             : char buffer[300];
     391             : 
     392             : if (keyGetBinary(key,buffer,sizeof(buffer)) == -1)
     393             : {
     394             :         // handle error
     395             : }
     396             :  * @endcode
     397             :  *
     398             :  * @param key the object to gather the value from
     399             :  * @param returnedBinary pre-allocated memory to store a copy of the key value
     400             :  * @param maxSize number of bytes of pre-allocated memory in @p returnedBinary
     401             :  * @return the number of bytes actually copied to @p returnedBinary
     402             :  * @retval 0 if the binary is empty
     403             :  * @retval -1 on NULL pointers
     404             :  * @retval -1 if maxSize is 0
     405             :  * @retval -1 if maxSize is too small for string
     406             :  * @retval -1 if maxSize is larger than SSIZE_MAX
     407             :  * @retval -1 on type mismatch: binary expected, but found string
     408             :  * @see keyValue(), keyGetValueSize(), keySetBinary()
     409             :  * @see keyGetString() and keySetString() as preferred alternative to binary
     410             :  * @see keyIsBinary() to see how to check for binary type
     411             :  * @ingroup keyvalue
     412             :  */
     413       91755 : ssize_t keyGetBinary (const Key * key, void * returnedBinary, size_t maxSize)
     414             : {
     415       91755 :         if (!key) return -1;
     416       91753 :         if (!returnedBinary) return -1;
     417       91751 :         if (!maxSize) return -1;
     418             : 
     419       91749 :         if (maxSize > SSIZE_MAX) return -1;
     420             : 
     421       91747 :         if (!keyIsBinary (key))
     422             :         {
     423             :                 /*errno=KDB_ERR_TYPEMISMATCH;*/
     424             :                 return -1;
     425             :         }
     426             : 
     427       91742 :         if (!key->data.v)
     428             :         {
     429             :                 return 0;
     430             :         }
     431             : 
     432       91724 :         if (key->dataSize > maxSize)
     433             :         {
     434             :                 /*errno=KDB_ERR_TRUNC;*/
     435             :                 return -1;
     436             :         }
     437             : 
     438       91698 :         memcpy (returnedBinary, key->data.v, key->dataSize);
     439       91698 :         return key->dataSize;
     440             : }
     441             : 
     442             : 
     443             : /**
     444             :  * Set the value of a key as a binary.
     445             :  *
     446             :  * A private copy of @p newBinary will allocated and saved inside @p key,
     447             :  * so the parameter can be deallocated after the call.
     448             :  *
     449             :  * Binary values might be encoded in another way then string values
     450             :  * depending on the plugin. Typically character encodings should not take
     451             :  * place on binary data.
     452             :  * Consider using a string key instead.
     453             :  *
     454             :  * When newBinary is a NULL pointer the binary will be freed and 0 will
     455             :  * be returned.
     456             :  *
     457             :  * @note The metadata "binary" will be set to mark that the key is
     458             :  * binary from now on. When the key is already binary the metadata
     459             :  * won't be changed. This will only happen in the successful case,
     460             :  * but not when -1 is returned.
     461             :  *
     462             :  * @param key the object on which to set the value
     463             :  * @param newBinary is a pointer to any binary data or NULL to free the previous set data
     464             :  * @param dataSize number of bytes to copy from @p newBinary
     465             :  * @return the number of bytes actually copied to internal struct storage
     466             :  * @retval 0 when the internal binary was freed and is now a null pointer
     467             :  * @retval -1 if key is a NULL pointer
     468             :  * @retval -1 when dataSize is 0 (but newBinary not NULL) or larger than SSIZE_MAX
     469             :  * @see keyGetBinary()
     470             :  * @see keyIsBinary() to check if the type is binary
     471             :  * @see keyGetString() and keySetString() as preferred alternative to binary
     472             :  * @ingroup keyvalue
     473             :  */
     474      241879 : ssize_t keySetBinary (Key * key, const void * newBinary, size_t dataSize)
     475             : {
     476      241879 :         ssize_t ret = 0;
     477             : 
     478      241879 :         if (!key) return -1;
     479             : 
     480      241877 :         if (!dataSize && newBinary) return -1;
     481      241870 :         if (dataSize > SSIZE_MAX) return -1;
     482      241862 :         if (key->flags & KEY_FLAG_RO_VALUE) return -1;
     483             : 
     484      241854 :         keySetMeta (key, "binary", "");
     485             : 
     486      241854 :         ret = keySetRaw (key, newBinary, dataSize);
     487             : 
     488             : 
     489      241854 :         return ret;
     490             : }
     491             : 
     492             : /**
     493             :  * @internal
     494             :  *
     495             :  * Set raw  data as the value of a key.
     496             :  * If NULL pointers are passed, key value is cleaned.
     497             :  * This method will not change or set the key type, and should only
     498             :  * be used internally in elektra.
     499             :  *
     500             :  * @param key the key object to work with
     501             :  * @param newBinary array of bytes to set as the value
     502             :  * @param dataSize number bytes to use from newBinary, including the final NULL
     503             :  * @return The number of bytes actually set in internal buffer.
     504             :  * @retval 1 if it was a string which was deleted
     505             :  * @retval 0 if it was a binary which was deleted
     506             :  * @see keySetType(), keySetString(), keySetBinary()
     507             :  * @ingroup keyvalue
     508             :  */
     509     1868500 : ssize_t keySetRaw (Key * key, const void * newBinary, size_t dataSize)
     510             : {
     511     1868500 :         if (!key) return -1;
     512     1868500 :         if (key->flags & KEY_FLAG_RO_VALUE) return -1;
     513             : 
     514     1868490 :         if (!dataSize || !newBinary)
     515             :         {
     516      278934 :                 if (key->data.v)
     517             :                 {
     518       61139 :                         if (!test_bit (key->flags, KEY_FLAG_MMAP_DATA)) elektraFree (key->data.v);
     519       61139 :                         key->data.v = NULL;
     520       61139 :                         clear_bit (key->flags, (keyflag_t) KEY_FLAG_MMAP_DATA);
     521             :                 }
     522      278934 :                 key->dataSize = 0;
     523      278934 :                 set_bit (key->flags, KEY_FLAG_SYNC);
     524      278934 :                 if (keyIsBinary (key)) return 0;
     525      278586 :                 return 1;
     526             :         }
     527             : 
     528     1589556 :         key->dataSize = dataSize;
     529     1589556 :         if (key->data.v)
     530             :         {
     531      324254 :                 char * previous = key->data.v;
     532             : 
     533      324254 :                 if (test_bit (key->flags, KEY_FLAG_MMAP_DATA))
     534             :                 {
     535           8 :                         clear_bit (key->flags, (keyflag_t) KEY_FLAG_MMAP_DATA);
     536           8 :                         key->data.v = elektraMalloc (key->dataSize);
     537           8 :                         if (key->data.v == NULL) return -1;
     538             :                 }
     539             :                 else
     540             :                 {
     541      324246 :                         if (-1 == elektraRealloc ((void **) &key->data.v, key->dataSize)) return -1;
     542             :                 }
     543             : 
     544      324254 :                 if (-1 == elektraRealloc ((void **) &key->data.v, key->dataSize)) return -1;
     545      324254 :                 if (previous == key->data.v)
     546             :                 {
     547             :                         // In case the regions overlap, use memmove to stay safe
     548      187846 :                         memmove (key->data.v, newBinary, key->dataSize);
     549             :                 }
     550             :                 else
     551             :                 {
     552      136408 :                         memcpy (key->data.v, newBinary, key->dataSize);
     553             :                 }
     554             :         }
     555             :         else
     556             :         {
     557     1265302 :                 char * p = elektraMalloc (key->dataSize);
     558     1265302 :                 if (NULL == p) return -1;
     559     1265302 :                 key->data.v = p;
     560     1265302 :                 memcpy (key->data.v, newBinary, key->dataSize);
     561             :         }
     562             : 
     563     1589556 :         set_bit (key->flags, KEY_FLAG_SYNC);
     564     1589556 :         return keyGetValueSize (key);
     565             : }

Generated by: LCOV version 1.13