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

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Methods for Key name manipulation.
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : /** @class doxygenNamespaces
      10             :  *
      11             :  * @brief .
      12             :  *
      13             :  * .
      14             :  *
      15             :  * - @p spec/something for specification of other keys.
      16             :  * - @p proc/something for in-memory keys, e.g. commandline.
      17             :  * - @p dir/something for dir keys in current working directory
      18             :  * - @p system/something for system keys in /etc or /
      19             :  * - @p user/something for user keys in home directory
      20             :  * - @p user:username/something for other users (deprecated: kdbGet() + kdbSet() currently unsupported)
      21             :  * - @p /something for cascading keys (actually refers to one of the above, see also ksLookup())
      22             :  *
      23             :  */
      24             : 
      25             : 
      26             : /**
      27             :  * @defgroup keyname Name Manipulation Methods
      28             :  * @ingroup key
      29             :  * @brief Methods to do various operations on Key names.
      30             :  *
      31             :  * To use them:
      32             :  * @code
      33             : #include <kdb.h>
      34             : * @endcode
      35             :  *
      36             :  * These functions make it easier for C programmers to work with key names.
      37             :  *
      38             :  *
      39             :  * @par Terminology of Key Names
      40             :  * - A *key name* (see keySetName() and keyName()) defines the
      41             :  *   place of a key within the key database.
      42             :  *   To be unique, it is always absolute and canonical.
      43             :  * - Key names are composed out of many *key name parts* split by a
      44             :  *   separator. These *key name parts* do not contain an unescaped
      45             :  *   separator.
      46             :  * - A *key base name* (see keySetBaseName() and keyAddBaseName()) is
      47             :  *   the last part of the key name.
      48             :  * - A *C-String* is a null terminated sequence of characters.
      49             :  *   So \\0 (null-character) must not occur within a C-String.
      50             :  *
      51             :  * @par Namespaces
      52             :  * A namespace denotes the place the key comes from:
      53             :  *
      54             :  * @copydetails doxygenNamespaces
      55             :  *
      56             :  *
      57             :  * @note The rules are currently not formally specified and are subject
      58             :  * of change in the next major release.
      59             :  * So, always prefer:
      60             :  * - To use keySetName() and keyAddName() to get the canonified version of the keyname
      61             :  * - To use keySetBaseName() and keyAddBaseName() to get an escaped key
      62             :  *   name part.
      63             :  * - Not to escape or canonify with your own algorithms!
      64             :  * - To use keyUnescapedName() and keyBaseName() to have access to the
      65             :  *   key name without escape sequences (key name parts are null
      66             :  *   terminated)
      67             :  * - Not to unescape the strings yourself!
      68             :  *
      69             :  *
      70             :  * @par Syntax for Key Names
      71             :  * Key names and key name parts have following goals:
      72             :  * - The C-String passed to keySetName() and keyAddName() may be any
      73             :  *   C-String.
      74             :  * - The *key name parts* (e.g. keySetBaseName(), keyBaseName()) may
      75             :  *   be any C-String.
      76             :  * Escaping is needed to achieve both goals.
      77             :  *
      78             :  *
      79             :  * @par Semantics for Key Name Parts
      80             :  * - \% denotes an empty key name part.
      81             :  *
      82             :  *
      83             :  * @par Canonicalization for Key Names
      84             :  * - / (slash) is the separator between key name parts.
      85             :  * - // is shortened to /
      86             :  * - trailing / (slashes) are removed
      87             :  * - . (dot) and .. (dot-dot) is removed in an canonical key name, with
      88             :  *   following rules:
      89             :  *   - /./ is shortened to /
      90             :  *   - _/../ is shortened to _
      91             :  *
      92             :  *
      93             :  * @par Conventions for key names
      94             :  * - Key name parts starting with \# are array elements.
      95             :  *   Then only _ (underscore) followed by 0-9 is allowed.
      96             :  *   So we have the regular expression #[_]*[0-9]+ with the further
      97             :  *   limitation that the number of _ is defined by the number of
      98             :  *   digits-1.
      99             :  * - Key name parts starting with _ are reserved for special purposes
     100             :  *   (if you use this within a plugin you still have to make sure _ is
     101             :  *   escaped properly)
     102             :  * - Key name parts starting with @ are reserved for special purposes
     103             :  *   (if you use this within a plugin you still have to make sure @ is
     104             :  *   escaped properly)
     105             :  * - If any key name part starts with . (dot) it means the key is
     106             :  *   inactive, see keyIsInactive().
     107             :  *
     108             :  *
     109             :  * @par Escaping rules
     110             :  * - \\ (backslash) is the escape character for the situations as
     111             :  *   described here (and only these).
     112             :  *   The \\ character must only be escaped, when one of the following
     113             :  *   rules apply.
     114             :  * - Stray escape characters are only possible in the end of the string.
     115             :  * - \\/ allows one to escape / (any uneven number of \\).
     116             :  *   Does not introduce a new part.
     117             :  * - Any uneven number N of \\ before / allows you to escape / with the
     118             :  *   N/2 of \\ prefixed.
     119             :  *   Does not introduce a new part.
     120             :  * - \\\\/ allows one to use \\ as character before / and introduces a new
     121             :  *   part.
     122             :  * - Any even number N of \\ before / allows you to have N/2 of \\
     123             :  *   prefixed before a / which introduces a new part.
     124             :  * - Use \\. and \\.. if you want your key name part to represent . and ..
     125             :  * - \\\\. and \\\\.. allows us to use \\ as character before . and .. (and so on)
     126             :  * - Use \\% if you want your key name part to start with \% (and does
     127             :  *   not represent an empty name)
     128             :  * - Using \\\\% allows one to use \\ as character before \% (and so on)
     129             : 
     130             :  *
     131             :  *
     132             :  * @par Semantics for Key Name Specifications
     133             :  * - _ denotes that the key name part is
     134             :  *   arbitrary (syntax as described above).
     135             :  * - \# denotes that the key name part
     136             :  *   has array syntax.
     137             :  * - names surrounded by \% (e.g. \%profile\%)
     138             :  *   denotes a placeholder.
     139             :  *
     140             :  *
     141             :  * @{
     142             :  */
     143             : 
     144             : 
     145             : #ifdef HAVE_KDBCONFIG_H
     146             : #include "kdbconfig.h"
     147             : #endif
     148             : 
     149             : #include <kdbassert.h>
     150             : 
     151             : #ifdef HAVE_STDARG_H
     152             : #include <stdarg.h>
     153             : #endif
     154             : 
     155             : #ifdef HAVE_STRING_H
     156             : #include <string.h>
     157             : #endif
     158             : 
     159             : #ifdef HAVE_STDLIB_H
     160             : #include <stdlib.h>
     161             : #endif
     162             : 
     163             : #include "kdb.h"
     164             : #include "kdbhelper.h"
     165             : #include "kdbinternal.h"
     166             : 
     167             : 
     168             : /*******************************************
     169             :  *    General name manipulation methods    *
     170             :  *******************************************/
     171             : 
     172             : 
     173             : /**
     174             :  * Returns a pointer to the abbreviated real internal @p key name.
     175             :  *
     176             :  * This is a much more efficient version of keyGetName() and can use
     177             :  * it if you are responsible enough to not mess up things. You are not allowed
     178             :  * to change anything in the returned array. The content of that string
     179             :  * may change after keySetName() and similar functions. If you need a copy of the name,
     180             :  * consider using keyGetName().
     181             :  *
     182             :  * The name will be without owner, see keyGetFullName() if
     183             :  * you need the name with its owner.
     184             :  *
     185             :  * @retval "" when there is no keyName. The reason is
     186             :  * @code
     187             : key=keyNew(0);
     188             : keySetName(key,"");
     189             : keyName(key); // you would expect "" here
     190             : keyDel(key);
     191             :  * @endcode
     192             :  *
     193             :  * Valid key names are:
     194             :  *
     195             :  * @copydetails doxygenNamespaces
     196             :  *
     197             :  * @note Note that the Key structure keeps its own size field that is calculated
     198             :  * by library internal calls, so to avoid inconsistencies, you
     199             :  * must never use the pointer returned by keyName() method to set a new
     200             :  * value. Use keySetName() instead.
     201             :  *
     202             :  * @param key the key object to work with
     203             :  * @return a pointer to the keyname which must not be changed.
     204             :  * @retval "" when there is no (an empty) keyname
     205             :  * @retval 0 on NULL pointer
     206             :  * @see keyGetNameSize() for the string length
     207             :  * @see keyGetFullName(), keyGetFullNameSize() to get the full name
     208             :  * @see keyGetName() as alternative to get a copy
     209             :  * @see keyOwner() to get a pointer to owner
     210             :  * @see keyUnescapedName to get an unescaped key name
     211             :  * @ingroup keyname
     212             :  */
     213     5998850 : const char * keyName (const Key * key)
     214             : {
     215     5998850 :         if (!key) return 0;
     216             : 
     217     5998741 :         if (!key->key)
     218             :         {
     219             :                 return "";
     220             :         }
     221             : 
     222     5967772 :         return key->key;
     223             : }
     224             : 
     225             : /**
     226             :  * Bytes needed to store the key name without owner.
     227             :  *
     228             :  * For an empty key name you need one byte to store the ending NULL.
     229             :  * For that reason 1 is returned.
     230             :  *
     231             :  * @param key the key object to work with
     232             :  * @return number of bytes needed, including ending NULL, to store key name
     233             :  *      without owner
     234             :  * @retval 1 if there is is no key Name
     235             :  * @retval -1 on NULL pointer
     236             :  * @see keyGetName(), keyGetFullNameSize()
     237             :  * @see keyGetUnescapedNameSize to get size of unescaped name
     238             :  * @ingroup keyname
     239             :  */
     240      846126 : ssize_t keyGetNameSize (const Key * key)
     241             : {
     242      846126 :         if (!key) return -1;
     243             : 
     244      759249 :         if (!key->key)
     245             :         {
     246             :                 return 1;
     247             :         }
     248             :         else
     249      759175 :                 return key->keySize;
     250             : }
     251             : 
     252             : 
     253             : /**
     254             :  * @brief Returns a keyname which is null separated and does not use backslash for escaping
     255             :  *
     256             :  * Slashes are replaced with null bytes.
     257             :  * So cascading keys start with a null byte.
     258             :  * Otherwise escaped characters, e.g. non-hierarchy slash, will be unescaped.
     259             :  *
     260             :  * This name is essential if you want to iterate over parts of the key
     261             :  * name, want to compare keynames and want to check relations of keys in
     262             :  * the hierarchy.
     263             :  *
     264             :  * @param key the object to work with
     265             :  *
     266             :  * @see keyGetUnescapedNameSize()
     267             :  * @see keyName() for escaped variant
     268             :  * @retval 0 on null pointers
     269             :  * @retval "" if no name
     270             :  * @return the name in its unescaped form
     271             :  */
     272     7317912 : const void * keyUnescapedName (const Key * key)
     273             : {
     274     7317912 :         if (!key) return 0;
     275             : 
     276     7317912 :         if (!key->key)
     277             :         {
     278             :                 return "";
     279             :         }
     280             : 
     281     7317830 :         return key->key + key->keySize;
     282             : }
     283             : 
     284             : 
     285             : /**
     286             :  * @brief return size of unescaped name with embedded and terminating null characters
     287             :  *
     288             :  * @param key the object to work with
     289             :  *
     290             :  * @see keyUnescapedName()
     291             :  * @see keyGetNameSize() for size of escaped variant
     292             :  * @retval -1 on null pointer
     293             :  * @retval 0 if no name
     294             :  */
     295     8002622 : ssize_t keyGetUnescapedNameSize (const Key * key)
     296             : {
     297     8002622 :         if (!key) return -1;
     298             : 
     299     8002622 :         if (!key->key)
     300             :         {
     301             :                 return 0;
     302             :         }
     303             :         else
     304     8002540 :                 return key->keyUSize;
     305             : }
     306             : 
     307             : 
     308             : /**
     309             :  * Get abbreviated key name (without owner name).
     310             :  *
     311             :  * When there is not enough space to write the name,
     312             :  * nothing will be written and -1 will be returned.
     313             :  *
     314             :  * maxSize is limited to SSIZE_MAX. When this value
     315             :  * is exceeded -1 will be returned. The reason for that
     316             :  * is that any value higher is just a negative return
     317             :  * value passed by accident. Of course elektraMalloc is not
     318             :  * as failure tolerant and will try to allocate.
     319             :  *
     320             :  * @code
     321             : char *getBack = elektraMalloc (keyGetNameSize(key));
     322             : keyGetName(key, getBack, keyGetNameSize(key));
     323             :  * @endcode
     324             :  *
     325             :  * @return number of bytes written to @p returnedName
     326             :  * @retval 1 when only a null was written
     327             :  * @retval -1 when keyname is longer then maxSize or 0 or any NULL pointer
     328             :  * @param key the key object to work with
     329             :  * @param returnedName pre-allocated memory to write the key name
     330             :  * @param maxSize maximum number of bytes that will fit in returnedName, including the final NULL
     331             :  * @see keyGetNameSize(), keyGetFullName(), keyGetFullNameSize()
     332             :  * @ingroup keyname
     333             :  */
     334        5209 : ssize_t keyGetName (const Key * key, char * returnedName, size_t maxSize)
     335             : {
     336        5209 :         if (!key) return -1;
     337             : 
     338        5207 :         if (!returnedName) return -1;
     339             : 
     340        5205 :         if (!maxSize) return -1;
     341             : 
     342        5201 :         if (maxSize > SSIZE_MAX) return -1;
     343             : 
     344        5199 :         if (!key->key)
     345             :         {
     346             :                 /*errno=KDB_ERR_NOKEY;*/
     347           4 :                 returnedName[0] = 0;
     348           4 :                 return 1;
     349             :         }
     350             : 
     351        5195 :         if (key->keySize > maxSize)
     352             :         {
     353             :                 /*errno=KDB_ERR_TRUNC;*/
     354             :                 return -1;
     355             :         }
     356             : 
     357        5177 :         strncpy (returnedName, key->key, maxSize);
     358             : 
     359        5177 :         return key->keySize;
     360             : }
     361             : 
     362             : /**
     363             :  * @internal
     364             :  *
     365             :  * @brief Call this function after every key name changing operation
     366             :  *
     367             :  * @pre key->key and key->keySize are set accordingly and the size of
     368             :  * allocation is twice as what you actually needed.
     369             :  *
     370             :  * @post we get a unsynced key with a correctly terminated
     371             :  * key name suitable for ordering and the name getter methods
     372             :  *
     373             :  * It will duplicate the key length and put a second name afterwards
     374             :  * that is used for sorting keys.
     375             :  *
     376             :  * @param key
     377             :  */
     378    14421331 : ssize_t elektraFinalizeName (Key * key)
     379             : {
     380    14421331 :         key->key[key->keySize - 1] = 0; /* finalize string */
     381             : 
     382    14421331 :         key->keyUSize = elektraUnescapeKeyName (key->key, key->key + key->keySize);
     383             : 
     384    14421331 :         key->flags |= KEY_FLAG_SYNC;
     385             : 
     386    14421331 :         return key->keySize;
     387             : }
     388             : 
     389      178990 : ssize_t elektraFinalizeEmptyName (Key * key)
     390             : {
     391      178990 :         key->key = elektraCalloc (2); // two null pointers
     392      178990 :         key->keySize = 1;
     393      178990 :         key->keyUSize = 1;
     394      178990 :         key->flags |= KEY_FLAG_SYNC;
     395             : 
     396      178990 :         return key->keySize;
     397             : }
     398             : 
     399      525921 : static void elektraHandleUserName (Key * key, const char * newName)
     400             : {
     401      525921 :         const size_t userLength = sizeof ("user");
     402      525921 :         key->keyUSize = key->keySize = userLength;
     403             : 
     404      525921 :         const char delim = newName[userLength - 1];
     405             :         // no owner, we are finished
     406      525921 :         if (delim == '/' || delim == '\0') return;
     407        1942 :         ELEKTRA_ASSERT (delim == ':', "delimiter in user-name not `:' but `%c'", delim);
     408             : 
     409             :         // handle owner (compatibility, to be removed)
     410        1942 :         keyNameGetOneLevel (newName, &key->keyUSize);
     411        1942 :         const size_t ownerLength = key->keyUSize - userLength;
     412        1942 :         ++key->keyUSize;
     413        1942 :         char * owner = elektraMalloc (ownerLength + 1);
     414        1942 :         if (!owner) return; // out of memory, ok for owner
     415        1942 :         strncpy (owner, newName + userLength, ownerLength);
     416        1942 :         owner[ownerLength] = 0;
     417        1942 :         keySetOwner (key, owner);
     418        1942 :         elektraFree (owner);
     419             : }
     420             : 
     421     9754701 : static void elektraRemoveKeyName (Key * key)
     422             : {
     423     9754701 :         if (key->key && !test_bit (key->flags, KEY_FLAG_MMAP_KEY)) elektraFree (key->key);
     424     9754701 :         clear_bit (key->flags, (keyflag_t) KEY_FLAG_MMAP_KEY);
     425     9754701 :         key->key = 0;
     426     9754701 :         key->keySize = 0;
     427     9754701 :         key->keyUSize = 0;
     428     9754701 : }
     429             : 
     430             : /**
     431             :  * @brief Checks if in name is something else other than slashes
     432             :  *
     433             :  * @param name the name to check
     434             :  *
     435             :  * @retval 0 if not only slashes
     436             :  * @retval 1 if only slashes
     437             :  */
     438             : static int elektraOnlySlashes (const char * name)
     439             : {
     440     6007532 :         size_t nameLen = strlen (name);
     441    12018878 :         for (size_t i = 0; i < nameLen; ++i)
     442             :         {
     443    12015427 :                 if (name[i] != '/') return 0; // not only slashes
     444             :         }
     445             :         return 1; // only slashes
     446             : }
     447             : 
     448             : 
     449             : /**
     450             :  * @internal
     451             :  */
     452    11638076 : static int keyGetNameNamespace (const char * name)
     453             : {
     454    11638076 :         if (!name) return KEY_NS_EMPTY;
     455    11621348 :         if (!strcmp (name, "")) return KEY_NS_EMPTY;
     456    11316006 :         if (name[0] == '/')
     457             :                 return KEY_NS_CASCADING;
     458    10686327 :         else if (keyNameIsSpec (name))
     459             :                 return KEY_NS_SPEC;
     460    10514812 :         else if (keyNameIsProc (name))
     461             :                 return KEY_NS_PROC;
     462    10510002 :         else if (keyNameIsDir (name))
     463             :                 return KEY_NS_DIR;
     464    10366160 :         else if (keyNameIsUser (name))
     465             :                 return KEY_NS_USER;
     466     9297149 :         else if (keyNameIsSystem (name))
     467             :                 return KEY_NS_SYSTEM;
     468     6154833 :         return KEY_NS_META;
     469             : }
     470             : 
     471             : 
     472             : /**
     473             :  * Set a new name to a key.
     474             :  *
     475             :  * A valid name is one of the forms:
     476             :  * @copydetails doxygenNamespaces
     477             :  *
     478             :  * An invalid name either has an invalid namespace or
     479             :  * a wrongly escaped \\ at the end of the name.
     480             :  *
     481             :  * See @link keyname key names @endlink for the exact rules.
     482             :  *
     483             :  * The last form has explicitly set the owner, to let the library
     484             :  * know in which user folder to save the key. A owner is a user name.
     485             :  * If it is not defined (the second form) current user is used.
     486             :  *
     487             :  * You should always follow the guidelines for key tree structure creation.
     488             :  *
     489             :  * A private copy of the key name will be stored, and the @p newName
     490             :  * parameter can be freed after this call.
     491             :  *
     492             :  * .., . and / will be handled as in filesystem paths. A valid name will be build
     493             :  * out of the (valid) name what you pass, e.g. user///sw/../sw//././MyApp -> user/sw/MyApp
     494             :  *
     495             :  * On invalid names, NULL or "" the name will be "" afterwards.
     496             :  *
     497             :  *
     498             :  * @retval size in bytes of this new key name including ending NULL
     499             :  * @retval 0 if newName is an empty string or a NULL pointer (name will be empty afterwards)
     500             :  * @retval -1 if newName is invalid (name will be empty afterwards)
     501             :  * @retval -1 if key was inserted to a keyset before
     502             :  * @param key the key object to work with
     503             :  * @param newName the new key name
     504             :  * @see keyNew(), keySetOwner()
     505             :  * @see keyGetName(), keyGetFullName(), keyName()
     506             :  * @see keySetBaseName(), keyAddBaseName() to manipulate a name
     507             :  * @ingroup keyname
     508             :  */
     509      736416 : ssize_t keySetName (Key * key, const char * newName)
     510             : {
     511      736416 :         return elektraKeySetName (key, newName, 0);
     512             : }
     513             : 
     514     9755325 : ssize_t elektraKeySetName (Key * key, const char * newName, option_t options)
     515             : {
     516     9755325 :         if (!key) return -1;
     517     9754738 :         if (test_bit (key->flags, KEY_FLAG_RO_NAME)) return -1;
     518             : 
     519     9754695 :         elektraRemoveKeyName (key);
     520     9754695 :         if (!(options & KEY_META_NAME)) keySetOwner (key, NULL);
     521             : 
     522     9754695 :         switch (keyGetNameNamespace (newName))
     523             :         {
     524             :         case KEY_NS_NONE:
     525           0 :                 ELEKTRA_ASSERT (0, "non empty key has no namespace?");
     526             :         case KEY_NS_EMPTY:
     527      178990 :                 elektraFinalizeEmptyName (key);
     528      178990 :                 return 0; // as documented
     529             :         case KEY_NS_CASCADING:
     530      592118 :                 key->keyUSize = 1;
     531      592118 :                 key->keySize = sizeof ("/");
     532      592118 :                 break;
     533             :         case KEY_NS_SPEC:
     534      107474 :                 key->keyUSize = key->keySize = sizeof ("spec");
     535      107474 :                 break;
     536             :         case KEY_NS_PROC:
     537        3578 :                 key->keyUSize = key->keySize = sizeof ("proc");
     538        3578 :                 break;
     539             :         case KEY_NS_DIR:
     540       89388 :                 key->keyUSize = key->keySize = sizeof ("dir");
     541       89388 :                 break;
     542             :         case KEY_NS_USER:
     543      525921 :                 elektraHandleUserName (key, newName);
     544      525921 :                 break;
     545             :         case KEY_NS_SYSTEM:
     546     2103491 :                 key->keyUSize = key->keySize = sizeof ("system");
     547     2103491 :                 break;
     548             :         case KEY_NS_META:
     549     6153735 :                 if (!(options & KEY_META_NAME)) return -1;
     550     6153619 :                 keyNameGetOneLevel (newName, &key->keySize);
     551     6153619 :                 key->keyUSize = ++key->keySize; // for null
     552     6153619 :                 break;
     553             :         } // Note that we abused keyUSize for cascading and user:owner
     554             : 
     555     9575589 :         const size_t length = elektraStrLen (newName);
     556     9575589 :         key->key = elektraMalloc (key->keySize * 2);
     557     9575589 :         memcpy (key->key, newName, key->keySize);
     558     9575589 :         if (length == key->keyUSize || length == key->keySize)
     559             :         { // use || because full length is keyUSize in user, but keySize for /
     560             :                 // newName consisted of root only
     561     3568057 :                 elektraFinalizeName (key);
     562     3568057 :                 return key->keyUSize;
     563             :         }
     564             : 
     565    12015064 :         if (elektraOnlySlashes (newName + key->keyUSize - 1))
     566             :         {
     567        3451 :                 elektraFinalizeName (key);
     568        3451 :                 return key->keySize;
     569             :         }
     570             : 
     571     6004081 :         key->key[key->keySize - 1] = '\0';
     572     6004081 :         const ssize_t ret = keyAddName (key, newName + key->keyUSize);
     573     6004081 :         if (ret == -1)
     574           6 :                 elektraRemoveKeyName (key);
     575             :         else
     576     6004075 :                 return key->keySize;
     577           6 :         return ret;
     578             : }
     579             : 
     580             : 
     581             : /**
     582             :  * Bytes needed to store the key name including user domain and ending NULL.
     583             :  *
     584             :  * @param key the key object to work with
     585             :  * @return number of bytes needed to store key name including user domain
     586             :  * @retval 1 on empty name
     587             :  * @retval -1 on NULL pointer
     588             :  * @see keyGetFullName(), keyGetNameSize()
     589             :  * @ingroup keyname
     590             :  */
     591        9125 : ssize_t keyGetFullNameSize (const Key * key)
     592             : {
     593        9125 :         size_t returnedSize = 0;
     594             : 
     595        9125 :         if (!key) return -1;
     596             : 
     597        9125 :         if (!key->key) return 1;
     598             : 
     599        9123 :         returnedSize = elektraStrLen (key->key);
     600             : 
     601        9123 :         if (keyNameIsUser (key->key) && keyGetMeta (key, "owner")) returnedSize += keyGetOwnerSize (key);
     602             : 
     603             :         /*
     604             :            After 2 elektraStrLen() calls looks like we counted one more NULL.
     605             :            But we need this byte count because a full key name has an
     606             :            additional ':' char.
     607             :         */
     608             : 
     609        9123 :         return returnedSize;
     610             : }
     611             : 
     612             : 
     613             : /**
     614             :  * Get key full name, including the user domain name.
     615             :  *
     616             :  * @return number of bytes written
     617             :  * @retval 1 on empty name
     618             :  * @retval -1 on NULL pointers
     619             :  * @retval -1 if maxSize is 0 or larger than SSIZE_MAX
     620             :  * @param key the key object
     621             :  * @param returnedName pre-allocated memory to write the key name
     622             :  * @param maxSize maximum number of bytes that will fit in returnedName, including the final NULL
     623             :  * @ingroup keyname
     624             :  */
     625        4463 : ssize_t keyGetFullName (const Key * key, char * returnedName, size_t maxSize)
     626             : {
     627        4463 :         size_t userSize = sizeof ("user") - 1;
     628             :         ssize_t length;
     629             :         ssize_t maxSSize;
     630             :         char * cursor;
     631             : 
     632        4463 :         if (!key) return -1;
     633        4461 :         if (!returnedName) return -1;
     634        4459 :         if (!maxSize) return -1;
     635             : 
     636        4455 :         if (maxSize > SSIZE_MAX) return -1;
     637        4453 :         maxSSize = maxSize;
     638             : 
     639        4453 :         length = keyGetFullNameSize (key);
     640        4453 :         if (length == 1)
     641             :         {
     642             :                 /*errno=KDB_ERR_NOKEY;*/
     643           2 :                 returnedName[0] = 0;
     644           2 :                 return length;
     645             :         }
     646        4451 :         else if (length < 0)
     647             :                 return length;
     648        4451 :         else if (length > maxSSize)
     649             :         {
     650             :                 /* errno=KDB_ERR_TRUNC; */
     651             :                 return -1;
     652             :         }
     653             : 
     654        4425 :         cursor = returnedName;
     655        4425 :         if (keyIsUser (key))
     656             :         {
     657        1769 :                 strncpy (cursor, key->key, userSize);
     658        1769 :                 cursor += userSize;
     659        1769 :                 if (keyGetMeta (key, "owner"))
     660             :                 {
     661          40 :                         *cursor = ':';
     662          40 :                         ++cursor;
     663          40 :                         size_t ownerSize = keyGetValueSize (keyGetMeta (key, "owner")) - 1;
     664          40 :                         strncpy (cursor, keyValue (keyGetMeta (key, "owner")), ownerSize);
     665          40 :                         cursor += ownerSize;
     666             :                 }
     667        1769 :                 strcpy (cursor, key->key + userSize);
     668             :         }
     669             :         else
     670        2656 :                 strcpy (cursor, key->key);
     671             : 
     672             :         return length;
     673             : }
     674             : 
     675             : 
     676             : /**
     677             :  * @brief Returns a pointer to the internal unescaped key name where the @p basename starts.
     678             :  *
     679             :  * This is a much more efficient version of keyGetBaseName() and you should
     680             :  * use it if you are responsible enough to not mess up things. The name might
     681             :  * change or even point to a wrong place after a keySetName(). So make
     682             :  * sure to copy the memory before the name changes.
     683             :  *
     684             :  * keyBaseName() returns "" when there is no keyBaseName. The reason is
     685             :  * @snippet testabi_key.c base0 empty
     686             :  *
     687             :  * And there is also support for really empty basenames:
     688             :  * @snippet testabi_key.c base1 empty
     689             :  *
     690             :  * @note You must never use the pointer returned by keyBaseName()
     691             :  * method to change the name, but you should use keySetBaseName()
     692             :  * instead.
     693             :  *
     694             :  * @note Do not assume that keyBaseName() points to the same region as
     695             :  * keyName() does.
     696             :  *
     697             :  * @param key the object to obtain the basename from
     698             :  * @return a pointer to the basename
     699             :  * @retval "" when the key has no (base)name
     700             :  * @retval 0 on NULL pointer
     701             :  * @see keyGetBaseName(), keyGetBaseNameSize()
     702             :  * @see keyName() to get a pointer to the name
     703             :  * @see keyOwner() to get a pointer to the owner
     704             :  * @ingroup keyname
     705             :  */
     706     1448252 : const char * keyBaseName (const Key * key)
     707             : {
     708     1448252 :         if (!key) return 0;
     709     1448244 :         if (!key->key) return "";
     710             : 
     711     1448237 :         char * p = key->key + key->keySize + key->keyUSize - 1;
     712             : 
     713     1448237 :         char * base = p;
     714     1448237 :         while (*(--p))
     715             :         {
     716             :                 base = p;
     717             :         }
     718             : 
     719     1448237 :         if (base != (key->key + key->keyUSize))
     720             :                 return base;
     721             :         else
     722         842 :                 return "";
     723             : }
     724             : 
     725             : 
     726             : /**
     727             :  * Calculates number of bytes needed to store basename of @p key.
     728             :  *
     729             :  * Key names that have only root names (e.g. @c "system" or @c "user"
     730             :  * or @c "user:domain" ) does not have basenames, thus the function will
     731             :  * return 1 bytes to store "".
     732             :  *
     733             :  * Basenames are denoted as:
     734             :  * - @c system/some/thing/basename -> @c basename
     735             :  * - @c user:domain/some/thing/base\\/name > @c base\\/name
     736             :  *
     737             :  * @param key the key object to work with
     738             :  * @return size in bytes of @p key's basename including ending NULL
     739             :  * @see keyBaseName(), keyGetBaseName()
     740             :  * @see keyName(), keyGetName(), keySetName()
     741             :  * @ingroup keyname
     742             :  */
     743       56086 : ssize_t keyGetBaseNameSize (const Key * key)
     744             : {
     745       56086 :         const char * baseName = keyBaseName (key);
     746       56086 :         if (!baseName) return -1;
     747             : 
     748       56086 :         return elektraStrLen (baseName);
     749             : }
     750             : 
     751             : 
     752             : /**
     753             :  * Calculate the basename of a key name and put it in @p returned finalizing
     754             :  * the string with NULL.
     755             :  *
     756             :  * Some examples:
     757             :  * - basename of @c system/some/keyname is @c keyname
     758             :  * - basename of @c "user/tmp/some key" is @c "some key"
     759             :  *
     760             :  * @param key the key to extract basename from
     761             :  * @param returned a pre-allocated buffer to store the basename
     762             :  * @param maxSize size of the @p returned buffer
     763             :  * @return number of bytes copied to @p returned
     764             :  * @retval 1 on empty name
     765             :  * @retval -1 on NULL pointers
     766             :  * @retval -1 when maxSize is 0 or larger than SSIZE_MAX
     767             :  * @see keyBaseName(), keyGetBaseNameSize()
     768             :  * @see keyName(), keyGetName(), keySetName()
     769             :  * @ingroup keyname
     770             :  */
     771        1140 : ssize_t keyGetBaseName (const Key * key, char * returned, size_t maxSize)
     772             : {
     773        1140 :         if (!key) return -1;
     774        1138 :         if (!returned) return -1;
     775        1136 :         if (!maxSize) return -1;
     776             : 
     777        1132 :         if (maxSize > SSIZE_MAX) return -1;
     778        1130 :         ssize_t maxSSize = maxSize;
     779             : 
     780        1130 :         if (!key->key)
     781             :         {
     782           2 :                 returned[0] = 0;
     783           2 :                 return 1;
     784             :         }
     785             : 
     786        1128 :         ssize_t baseSize = keyGetBaseNameSize (key);
     787        1128 :         if (maxSSize < baseSize)
     788             :         {
     789             :                 return -1;
     790             :         }
     791             : 
     792        1120 :         const char * baseName = keyBaseName (key);
     793             : 
     794        1120 :         if (!baseName)
     795             :         {
     796             :                 return -1;
     797             :         }
     798             : 
     799        1120 :         strncpy (returned, baseName, baseSize);
     800        1120 :         return baseSize;
     801             : }
     802             : 
     803             : 
     804             : /**
     805             :  * Adds @p baseName (that will be escaped) to the current key name.
     806             :  *
     807             :  * A new baseName will be added, no other part of the key name will be
     808             :  * affected.
     809             :  *
     810             :  * Assumes that @p key is a directory and will append @p baseName to it.
     811             :  * The function adds the path separator for concatenating.
     812             :  *
     813             :  * So if @p key has name @c "system/dir1/dir2" and this method is called with
     814             :  * @p baseName @c "mykey", the resulting key will have the name
     815             :  * @c "system/dir1/dir2/mykey".
     816             :  *
     817             :  * When @p baseName is 0 nothing will happen and the size of the name is returned.
     818             :  *
     819             :  * The escaping rules apply as in @link keyname above @endlink.
     820             :  *
     821             :  * A simple example is:
     822             :  * @snippet keyBasename.c add base basic
     823             :  *
     824             :  * E.g. if you add . it will be escaped:
     825             :  * @snippet testabi_key.c base1 add
     826             :  *
     827             :  * @see keySetBaseName() to set a base name
     828             :  * @see keySetName() to set a new name.
     829             :  *
     830             :  * @param key the key object to work with
     831             :  * @param baseName the string to append to the name
     832             :  * @return the size in bytes of the new key name including the ending NULL
     833             :  * @retval -1 if the key had no name
     834             :  * @retval -1 on NULL pointers
     835             :  * @retval -1 if key was inserted to a keyset before
     836             :  * @retval -1 on allocation errors
     837             :  * @ingroup keyname
     838             :  *
     839             :  */
     840      879662 : ssize_t keyAddBaseName (Key * key, const char * baseName)
     841             : {
     842      879662 :         if (!key) return -1;
     843      879636 :         if (!baseName) return key->keySize;
     844      879634 :         if (test_bit (key->flags, KEY_FLAG_RO_NAME)) return -1;
     845      879630 :         if (!key->key) return -1;
     846             : 
     847      879625 :         char * escaped = elektraMalloc (strlen (baseName) * 2 + 2);
     848      879625 :         elektraEscapeKeyNamePart (baseName, escaped);
     849      879625 :         size_t len = strlen (escaped);
     850      879625 :         if (!strcmp (key->key, "/"))
     851             :         {
     852      151773 :                 key->keySize += len;
     853             :         }
     854             :         else
     855             :         {
     856      727852 :                 key->keySize += len + 1;
     857             :         }
     858             : 
     859      879625 :         const size_t newSize = key->keySize * 2;
     860      879625 :         if (test_bit (key->flags, KEY_FLAG_MMAP_KEY))
     861             :         {
     862             :                 // key was in mmap region, clear flag and trigger malloc instead of realloc
     863           0 :                 key->key = elektraMalloc (newSize);
     864           0 :                 clear_bit (key->flags, (keyflag_t) KEY_FLAG_MMAP_KEY);
     865             :         }
     866             :         else
     867             :         {
     868      879625 :                 if (-1 == elektraRealloc ((void **) &key->key, newSize)) return -1;
     869             :         }
     870             : 
     871      879625 :         if (!key->key)
     872             :         {
     873           0 :                 elektraFree (escaped);
     874           0 :                 return -1;
     875             :         }
     876             : 
     877      879625 :         if (strcmp (key->key, "/"))
     878             :         {
     879      727852 :                 key->key[key->keySize - len - 2] = KDB_PATH_SEPARATOR;
     880             :         }
     881      879625 :         memcpy (key->key + key->keySize - len - 1, escaped, len);
     882             : 
     883      879625 :         elektraFree (escaped);
     884             : 
     885      879625 :         elektraFinalizeName (key);
     886             : 
     887      879625 :         return key->keySize;
     888             : }
     889             : 
     890             : /**
     891             :  * @internal
     892             :  *
     893             :  * @brief Used by keyAddName
     894             :  *
     895             :  * Will remove one level of key, even if key->key is not null terminated
     896             :  * also handles cascading keys and sets avoidSlash properly.
     897             :  *
     898             :  * @param key to remove one level
     899             :  * @param [out] avoidSlash set to 1 if / is already present (cascading)
     900             :  */
     901      411237 : static void elektraRemoveOneLevel (Key * key, int * avoidSlash)
     902             : {
     903      411237 :         int levels = 0;
     904      411237 :         char * x = key->key;
     905      411237 :         size_t xsize = 0;
     906      411237 :         size_t sizeOfLastLevel = 0;
     907      411237 :         char * const last = &key->key[key->keySize];
     908      411237 :         const char save = *last;
     909      411237 :         *last = 0;
     910             : 
     911     2418027 :         while (*(x = keyNameGetOneLevel (x + xsize, &xsize)))
     912             :         {
     913     2006790 :                 sizeOfLastLevel = xsize;
     914     2006790 :                 levels++;
     915             :         }
     916             : 
     917      411237 :         if (levels > 1)
     918             :         {
     919      410378 :                 key->keySize -= sizeOfLastLevel + 1;
     920      410378 :                 key->key[key->keySize] = 0;
     921             :         }
     922         859 :         else if (*key->key == '/') // cascading key
     923             :         {
     924             :                 // strip down to root
     925         100 :                 key->keySize = 1;
     926         100 :                 *avoidSlash = 1;
     927             :         }
     928      411237 :         *last = save;
     929      411237 : }
     930             : 
     931             : /**
     932             :  * @brief Add an already escaped name to the keyname.
     933             :  *
     934             :  * The same way as in keySetName() this method finds the canonical pathname:
     935             :  * - it will ignore /./
     936             :  * - it will remove a level when /../ is used
     937             :  * - it will remove multiple slashes ////
     938             :  *
     939             :  * For example:
     940             :  * @snippet keyName.c add name
     941             :  *
     942             :  * Unlike keySetName() it adds relative to the previous name and
     943             :  * cannot change the namespace of a key.
     944             :  * For example:
     945             :  * @snippet keyName.c namespace
     946             :  *
     947             :  * The passed name needs to be valid according the @link keyname key name rules @endlink.
     948             :  * It is not allowed to:
     949             :  * - be empty
     950             :  * - end with unequal number of \\
     951             :  *
     952             :  * @param key the key where a name should be added
     953             :  * @param newName the new name to append
     954             :  *
     955             :  * @since 0.8.11
     956             :  *
     957             :  * @retval size of the new key
     958             :  * @retval -1 if key is a null pointer or did not have a valid name before
     959             :  * @retval -1 if newName is not a valid escaped name
     960             :  * @retval -1 on allocation errors
     961             :  * @retval -1 if key was inserted to a keyset before
     962             :  * @retval 0 if nothing was done because newName had only slashes, is too short, is empty or is null
     963             :  * @ingroup keyname
     964             :  */
     965     7320626 : ssize_t keyAddName (Key * key, const char * newName)
     966             : {
     967     7320626 :         if (!key) return -1;
     968     7320624 :         if (test_bit (key->flags, KEY_FLAG_RO_NAME)) return -1;
     969     7320620 :         if (!key->key) return -1;
     970     7320619 :         if (!strcmp (key->key, "")) return -1;
     971     7320617 :         if (!newName) return 0;
     972     7320611 :         size_t const nameSize = elektraStrLen (newName);
     973     7320611 :         if (nameSize < 2) return 0;
     974     7320404 :         if (!elektraValidateKeyName (newName, nameSize)) return -1;
     975             : 
     976     7320394 :         const size_t origSize = key->keySize;
     977     7320394 :         const size_t newSize = (origSize + nameSize) * 2;
     978             : 
     979     7320394 :         if (test_bit (key->flags, KEY_FLAG_MMAP_KEY))
     980             :         {
     981             :                 // key was in mmap region, clear flag and trigger malloc instead of realloc
     982           0 :                 key->key = elektraMalloc (newSize);
     983           0 :                 clear_bit (key->flags, (keyflag_t) KEY_FLAG_MMAP_KEY);
     984             :         }
     985             :         else
     986             :         {
     987     7320394 :                 if (-1 == elektraRealloc ((void **) &key->key, newSize)) return -1;
     988             :         }
     989             : 
     990     7320394 :         if (!key->key) return -1;
     991             : 
     992     7320394 :         size_t size = 0;
     993     7320394 :         const char * p = newName;
     994     7320394 :         int avoidSlash = 0;
     995             : 
     996     7320394 :         if (*key->key == '/') avoidSlash = key->keySize == 2;
     997             : 
     998     7320394 :         --key->keySize; // loop assumes that key->key[key->keySize] is last character and not NULL
     999             : 
    1000             :         /* iterate over each single folder name removing repeated '/', .  and .. */
    1001    30368617 :         while (*(p = keyNameGetOneLevel (p + size, &size)))
    1002             :         {
    1003    15727829 :                 if (size == 1 && strncmp (p, ".", 1) == 0)
    1004             :                 {
    1005         982 :                         continue; /* just ignore current directory */
    1006             :                 }
    1007    15726847 :                 else if (size == 2 && strncmp (p, "..", 2) == 0) /* give away one level*/
    1008             :                 {
    1009      411237 :                         elektraRemoveOneLevel (key, &avoidSlash);
    1010      411237 :                         continue;
    1011             :                 }
    1012             : 
    1013    15315610 :                 if (!avoidSlash)
    1014             :                 {
    1015             :                         /* Add a '/' to the end of key name */
    1016    14875583 :                         key->key[key->keySize] = KDB_PATH_SEPARATOR;
    1017    14875583 :                         key->keySize++;
    1018             :                 }
    1019             :                 else
    1020             :                 {
    1021      440027 :                         avoidSlash = 0;
    1022             :                 }
    1023             : 
    1024             :                 /* carefully append basenames */
    1025    15315610 :                 char * d = key->key + key->keySize;
    1026    15315610 :                 memcpy (d, p, size);
    1027    15315610 :                 key->keySize += size;
    1028             :         }
    1029             : 
    1030     7320394 :         ++key->keySize; /*for \\0 ending*/
    1031             : 
    1032     7320394 :         elektraFinalizeName (key);
    1033             : 
    1034     7320394 :         return origSize == key->keySize ? 0 : key->keySize;
    1035             : }
    1036             : 
    1037             : 
    1038             : /**
    1039             :  * Sets @c baseName as the new basename for @c key.
    1040             :  *
    1041             :  * Only the baseName will be affected and no other part of the key.
    1042             :  *
    1043             :  * A simple example is:
    1044             :  * @snippet keyBasename.c set base basic
    1045             :  *
    1046             :  * All text after the last @c '/' in the @p key keyname is erased and
    1047             :  * @p baseName is appended.
    1048             :  * If @p baseName is 0 (NULL), then the last part of the keyname is
    1049             :  * removed without replacement.
    1050             :  *
    1051             :  * Let us suppose @p key has name @c "system/dir1/dir2/key1". If @p baseName
    1052             :  * is @c "key2", the resulting key name will be @c "system/dir1/dir2/key2".
    1053             :  * If @p baseName is 0 (NULL), the resulting key name will
    1054             :  * be @c "system/dir1/dir2".
    1055             :  * If @p baseName is empty, the resulting key name will
    1056             :  * be @c "system/dir1/dir2/%", where @c "%" denotes an empty base name,
    1057             :  * as also shown in the following code:
    1058             :  *
    1059             :  * @snippet testabi_key.c base2
    1060             :  *
    1061             :  * keySetBaseName() does proper escaping on the supplied name argument.
    1062             :  *
    1063             :  * You can use character sequences as @c baseName (e.g. @c "." (dot), @c ".."
    1064             :  * (dot-dot), @c "%" (empty basename)). They will be properly escaped
    1065             :  * and will not have their usual meaning.
    1066             :  *
    1067             :  * @see keyname for more details on special names
    1068             :  *
    1069             :  * If you want to add and not change the basename, use keyAddBaseName()
    1070             :  * instead. If you do not want escaping, use keyAddName() instead.
    1071             :  *
    1072             :  * @see keyAddBaseName() to add a basename instead of changing it
    1073             :  * @see keyAddName() to add a name without escaping
    1074             :  * @see keySetName() to set a completely new name
    1075             :  *
    1076             :  * To add an inactive key name, use:
    1077             :  * @snippet testabi_key.c base1
    1078             :  *
    1079             :  * @param key the key object to work with
    1080             :  * @param baseName the string used to overwrite the basename of the key
    1081             :  * @return the size in bytes of the new key name
    1082             :  * @retval -1 on NULL pointers in key
    1083             :  * @retval -1 if key was inserted to a keyset before
    1084             :  * @retval -1 on allocation errors
    1085             :  * @ingroup keyname
    1086             :  */
    1087      328730 : ssize_t keySetBaseName (Key * key, const char * baseName)
    1088             : {
    1089      328730 :         if (!key) return -1;
    1090      328730 :         if (test_bit (key->flags, KEY_FLAG_RO_NAME)) return -1;
    1091      328724 :         if (!key->key) return -1;
    1092             : 
    1093      328721 :         size_t size = 0;
    1094      328721 :         char * searchBaseName = 0;
    1095      328721 :         size_t searchBaseSize = 0;
    1096      328721 :         char * p = key->key;
    1097             : 
    1098     1811214 :         while (*(p = keyNameGetOneLevel (p + size, &size)))
    1099             :         {
    1100     1153772 :                 searchBaseName = p;
    1101     1153772 :                 searchBaseSize = size + 1;
    1102             :         }
    1103             : 
    1104      328721 :         if (!searchBaseName || searchBaseName == key->key)
    1105             :         {
    1106             :                 return -1;
    1107             :         }
    1108             : 
    1109             :         // truncate the key
    1110      328390 :         key->keySize -= searchBaseSize;
    1111             : 
    1112      328390 :         if (!baseName)
    1113             :         {
    1114             :                 // Avoid deleting the last / of a cascading key by increasing the size by one again
    1115        8586 :                 key->keySize += (1 == key->keySize) && (KEY_NS_CASCADING == keyGetNamespace (key));
    1116             : 
    1117             :                 // just remove base name, so we are finished
    1118        8586 :                 elektraFinalizeName (key);
    1119        8586 :                 return key->keySize;
    1120             :         }
    1121             : 
    1122      319804 :         char * escaped = elektraMalloc (strlen (baseName) * 2 + 2);
    1123      319804 :         elektraEscapeKeyNamePart (baseName, escaped);
    1124      319804 :         size_t sizeEscaped = elektraStrLen (escaped);
    1125             : 
    1126      319804 :         const size_t newSize = (key->keySize + sizeEscaped) * 2;
    1127      319804 :         if (test_bit (key->flags, KEY_FLAG_MMAP_KEY))
    1128             :         {
    1129             :                 // key was in mmap region, clear flag and trigger malloc instead of realloc
    1130           0 :                 key->key = elektraMalloc (newSize);
    1131           0 :                 clear_bit (key->flags, (keyflag_t) KEY_FLAG_MMAP_KEY);
    1132             :         }
    1133             :         else
    1134             :         {
    1135      319804 :                 if (-1 == elektraRealloc ((void **) &key->key, newSize)) return -1;
    1136             :         }
    1137             : 
    1138      319804 :         if (!key->key)
    1139             :         {
    1140           0 :                 elektraFree (escaped);
    1141           0 :                 return -1;
    1142             :         }
    1143             : 
    1144      319804 :         key->key[key->keySize - 1] = KDB_PATH_SEPARATOR;
    1145      319804 :         memcpy (key->key + key->keySize, escaped, sizeEscaped);
    1146             : 
    1147      319804 :         elektraFree (escaped);
    1148             : 
    1149      319804 :         key->keySize += sizeEscaped;
    1150      319804 :         elektraFinalizeName (key);
    1151             : 
    1152      319804 :         return key->keySize;
    1153             : }
    1154             : 
    1155             : /**
    1156             :  * For currently valid namespaces see #elektraNamespace.
    1157             :  *
    1158             :  * @since 0.8.10
    1159             :  * Added method to kdbproposal.h
    1160             :  *
    1161             :  * To handle every possible cases (including namespaces) a key can have:
    1162             :  * @snippet namespace.c namespace
    1163             :  *
    1164             :  * To loop over all valid namespaces use:
    1165             :  * @snippet namespace.c loop
    1166             :  *
    1167             :  * @note This method might be enhanced. You do not have any guarantee
    1168             :  * that, when for a specific name #KEY_NS_META
    1169             :  * is returned today, that it still will be returned after the next
    1170             :  * recompilation. So make sure that your compiler gives you a warning
    1171             :  * for unhandled switches (gcc: -Wswitch or -Wswitch-enum if you
    1172             :  * want to handle default) and look out for those warnings.
    1173             :  *
    1174             :  * @param key the key object to work with
    1175             :  * @return the namespace of a key.
    1176             :  */
    1177     1883591 : elektraNamespace keyGetNamespace (const Key * key)
    1178             : {
    1179     1883591 :         if (!key) return KEY_NS_NONE;
    1180     1883381 :         return keyGetNameNamespace (key->key);
    1181             : }
    1182             : 
    1183             : 
    1184             : /**
    1185             :  * @}
    1186             :  */

Generated by: LCOV version 1.13