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

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Helpers for key manipulation.
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : #ifdef HAVE_KDBCONFIG_H
      10             : #include "kdbconfig.h"
      11             : #endif
      12             : 
      13             : #include <stdio.h>
      14             : 
      15             : #ifdef HAVE_STDARG_H
      16             : #include <stdarg.h>
      17             : #endif
      18             : 
      19             : #ifdef HAVE_STRING_H
      20             : #include <string.h>
      21             : #endif
      22             : 
      23             : #ifdef HAVE_STDLIB_H
      24             : #include <stdlib.h>
      25             : #endif
      26             : 
      27             : 
      28             : #include "kdb.h"
      29             : #include "kdbprivate.h"
      30             : #include "kdbtypes.h"
      31             : #include <kdbassert.h>
      32             : 
      33             : 
      34             : /**
      35             :  * @internal
      36             :  *
      37             :  * Returns one level of the escaped key name.
      38             :  *
      39             :  * Only needed for escaping engine, otherwise the unescaped key name
      40             :  * should be used! In the unescaped version, every level is null
      41             :  * terminated.
      42             :  *
      43             :  * Interface is not const-correct. It does a const-cast needed for
      44             :  * many clients.
      45             :  *
      46             :  * This method is used to skip repeating '/' and to find escaping chars.
      47             :  * Given @p keyName, this method returns a pointer to the next name level
      48             :  * found and changes @p size to the number of bytes on this level name.
      49             :  *
      50             :  * This method is used by keySetName() to cleanup parameters
      51             :  * before being accepted in the Key object.
      52             :  *
      53             :  * @code
      54             : // Lets define a key name with a lot of repeating '/' and escaped '/'
      55             : char *keyName="user////abc/def\/ghi////jkl///";
      56             : char *p=keyName;
      57             : size_t size=0;
      58             : int level=0;
      59             : char buffer[20]; // TODO: make sure buffer size is ok
      60             : 
      61             : p=keyName;
      62             : while (*(p=keyNameGetOneLevel(p+size,&size)))
      63             : {
      64             :         level++;
      65             : 
      66             :         // copy what we found to a buffer, so we can NULL-terminate it
      67             :         strncpy(buffer,p,size);
      68             :         buffer[size]=0;
      69             : 
      70             :         printf("Level %d name: \"%s\"\n",level,buffer);
      71             : }
      72             : 
      73             :  * The above example will produce the following output:
      74             :  *
      75             :  * @code
      76             : Level 1 name: user
      77             : Level 2 name: abc
      78             : Level 3 name: def\/ghi
      79             : Level 4 name: jkl
      80             :  * @endcode
      81             :  *
      82             :  * @pre name must be non-null and point to a null terminated string
      83             :  *
      84             :  * @param name the string that will be searched
      85             :  * @param size the number of bytes of level name found in @p keyName until
      86             :  *      the next delimiter ('/')
      87             :  * @return a pointer to the first char of the next level name, it will point to
      88             :  *      NULL when done.
      89             :  * @ingroup keyname
      90             :  */
      91    38206704 : char * keyNameGetOneLevel (const char * name, size_t * size)
      92             : {
      93    38206704 :         char * real = (char *) name;
      94    38206704 :         size_t cursor = 0;
      95    38206704 :         int end = 0;     // bool to check for end of level
      96    38206704 :         int escapeCount = 0; // counter to check if / was escaped
      97             : 
      98             :         /* skip all repeating '/' in the beginning */
      99    90597640 :         while (*real && *real == KDB_PATH_SEPARATOR)
     100             :         {
     101    14184232 :                 ++real;
     102             :         }
     103             : 
     104             :         /* now see where this basename ends handling escaped chars with '\' */
     105   270850145 :         while (real[cursor] && !end)
     106             :         {
     107   232643441 :                 switch (real[cursor])
     108             :                 {
     109             :                 case KDB_PATH_ESCAPE:
     110     3575104 :                         ++escapeCount;
     111     3575104 :                         break;
     112             :                 case KDB_PATH_SEPARATOR:
     113    20774315 :                         if (!(escapeCount % 2))
     114             :                         {
     115    17213374 :                                 end = 1;
     116             :                         }
     117             :                 // fallthrough
     118             :                 default:
     119             :                         escapeCount = 0;
     120             :                 }
     121   232643441 :                 ++cursor;
     122             :         }
     123             : 
     124             :         /* if a '/' stopped our loop, balance the counter */
     125    38206704 :         if (end)
     126             :         {
     127    17213374 :                 --cursor;
     128             :         }
     129             : 
     130    38206704 :         *size = cursor;
     131    38206704 :         return real;
     132             : }
     133             : 
     134    10687040 : int keyNameIsSpec (const char * name)
     135             : {
     136    10687040 :         if (!strcmp ("spec", name) || !strncmp ("spec/", name, sizeof ("spec/") - 1)) return 1;
     137    10514821 :         return 0;
     138             : }
     139             : 
     140    10514812 : int keyNameIsProc (const char * name)
     141             : {
     142    10514812 :         if (!strcmp ("proc", name) || !strncmp ("proc/", name, sizeof ("proc/") - 1)) return 1;
     143    10510002 :         return 0;
     144             : }
     145             : 
     146    10510336 : int keyNameIsDir (const char * name)
     147             : {
     148    10510336 :         if (!strcmp ("dir", name) || !strncmp ("dir/", name, sizeof ("dir/") - 1)) return 1;
     149    10366170 :         return 0;
     150             : }
     151             : 
     152             : /**
     153             :  * @internal
     154             :  *
     155             :  * Check whether a key name is under the @p user namespace or not
     156             :  *
     157             :  * @return 1 if string begins with @p user, 0 otherwise
     158             :  * @param keyName the name of a key
     159             :  * @see keyIsSystem(), keyIsUser(), keyNameIsSystem()
     160             :  * @ingroup keyname
     161             :  *
     162             :  */
     163    11503903 : int keyNameIsUser (const char * name)
     164             : {
     165    11503903 :         if (!strcmp ("user", name) || !strncmp ("user/", name, sizeof ("user/") - 1) || !strncmp ("user:", name, sizeof ("user:") - 1))
     166             :         {
     167             :                 return 1;
     168             :         }
     169    10081371 :         return 0;
     170             : }
     171             : 
     172             : /**
     173             :  * @internal
     174             :  *
     175             :  * Check whether a key name is under the @p system namespace or not
     176             :  *
     177             :  * @return 1 if string begins with @p system , 0 otherwise
     178             :  * @param keyName the name of a key
     179             :  * @see keyIsSystem(), keyIsUser(), keyNameIsUser()
     180             :  * @ingroup keyname
     181             :  *
     182             :  */
     183    10525790 : int keyNameIsSystem (const char * name)
     184             : {
     185    10525790 :         if (!strcmp ("system", name) || !strncmp ("system/", name, sizeof ("system/") - 1)) return 1;
     186     6803797 :         return 0;
     187             : }
     188             : 
     189             : 
     190             : /**
     191             :  * @internal
     192             :  *
     193             :  * clears key (all data members are set to zero)
     194             :  */
     195    21988831 : int keyInit (Key * key)
     196             : {
     197    21988831 :         memset (key, 0, sizeof (struct _Key));
     198             : 
     199    21988831 :         return 0;
     200             : }
     201             : 
     202          27 : static int elektraSetMetaInt (Key * key, const char * meta, int value)
     203             : {
     204          27 :         char * str = 0;
     205          27 :         if ((str = elektraFormat ("%d", value)) == 0)
     206             :         {
     207             :                 return -1;
     208             :         }
     209             : 
     210          27 :         keySetMeta (key, meta, str);
     211          27 :         elektraFree (str);
     212          27 :         return 0;
     213             : }
     214             : 
     215             : // duplicate of keySetMode in meta/meta.c
     216        1427 : static int elektraSetMode (Key * key, mode_t mode)
     217             : {
     218             :         char str[MAX_LEN_INT];
     219        1427 :         if (!key) return -1;
     220             : 
     221        1427 :         if (snprintf (str, MAX_LEN_INT - 1, "%o", mode) < 0)
     222             :         {
     223             :                 return -1;
     224             :         }
     225             : 
     226        1427 :         keySetMeta (key, "mode", str);
     227             : 
     228        1427 :         return 0;
     229             : }
     230             : 
     231             : /**
     232             :  * @internal
     233             :  *
     234             :  * helper functions for keyNew/keyVNew
     235             :  *
     236             :  * @pre caller must use va_start and va_end on va
     237             :  * @param key initialized Key
     238             :  * @param keyName a valid name to the key, or NULL to get a simple
     239             :  * initialized, but really empty, object
     240             :  * @param va the variadic argument list
     241             :  */
     242     2213982 : void keyVInit (Key * key, const char * name, va_list va)
     243             : {
     244     2213982 :         if (!key) return;
     245             : 
     246     2213982 :         keyInit (key);
     247             : 
     248     2213982 :         if (name)
     249             :         {
     250     2213982 :                 keyswitch_t action = 0;
     251     2213982 :                 size_t value_size = 0;
     252     2213982 :                 void * value = 0;
     253     2213982 :                 void (*func) (void) = 0;
     254     2213982 :                 int flags = 0;
     255     2213982 :                 char * owner = 0;
     256     2213982 :                 int mode = 0;
     257     2213982 :                 int hasMode = 0;
     258             : 
     259     5625677 :                 while ((action = va_arg (va, keyswitch_t)))
     260             :                 {
     261     1197713 :                         switch (action)
     262             :                         {
     263             :                         /* flags with an argument */
     264             :                         case KEY_SIZE:
     265       57981 :                                 value_size = va_arg (va, size_t);
     266       57981 :                                 break;
     267             :                         case KEY_VALUE:
     268      887041 :                                 value = va_arg (va, void *);
     269      887041 :                                 if (value_size && keyIsBinary (key))
     270       57965 :                                         keySetBinary (key, value, value_size);
     271      829076 :                                 else if (keyIsBinary (key))
     272          15 :                                         keySetBinary (key, value, elektraStrLen (value));
     273             :                                 else
     274      829061 :                                         keySetString (key, value);
     275             :                                 break;
     276             :                         case KEY_FUNC:
     277      119203 :                                 func = va_arg (va, void (*) (void));
     278      119203 :                                 keySetBinary (key, &func, sizeof (func));
     279      119203 :                                 break;
     280             :                         case KEY_META:
     281       17827 :                                 value = va_arg (va, char *);
     282             :                                 /* First parameter is name */
     283       17827 :                                 keySetMeta (key, value, va_arg (va, char *));
     284       17827 :                                 break;
     285             : 
     286             :                         /* flags without an argument */
     287             :                         case KEY_FLAGS:
     288         304 :                                 flags |= va_arg (va, int); // FALLTHROUGH
     289             :                         case KEY_BINARY:
     290             :                         case KEY_LOCK_NAME:
     291             :                         case KEY_LOCK_VALUE:
     292             :                         case KEY_LOCK_META:
     293             :                         case KEY_CASCADING_NAME:
     294             :                         case KEY_META_NAME:
     295             :                         case KEY_EMPTY_NAME:
     296       97104 :                                 if (action != KEY_FLAGS) flags |= action;
     297       97104 :                                 if (test_bit (flags, KEY_BINARY)) keySetMeta (key, "binary", "");
     298       97104 :                                 if (test_bit (flags, KEY_LOCK_NAME)) elektraKeyLock (key, KEY_LOCK_NAME);
     299       97104 :                                 if (test_bit (flags, KEY_LOCK_VALUE)) elektraKeyLock (key, KEY_LOCK_VALUE);
     300       97104 :                                 if (test_bit (flags, KEY_LOCK_META)) elektraKeyLock (key, KEY_LOCK_META);
     301             :                                 break;
     302             : 
     303             :                         /* deprecated flags */
     304             :                         case KEY_NAME:
     305           0 :                                 name = va_arg (va, char *);
     306           0 :                                 break;
     307             :                         case KEY_OWNER:
     308          45 :                                 owner = va_arg (va, char *);
     309          45 :                                 break;
     310             :                         case KEY_COMMENT:
     311       17053 :                                 keySetMeta (key, "comment", va_arg (va, char *));
     312       17053 :                                 break;
     313             :                         case KEY_UID:
     314          15 :                                 elektraSetMetaInt (key, "uid", va_arg (va, int));
     315          15 :                                 break;
     316             :                         case KEY_GID:
     317           9 :                                 elektraSetMetaInt (key, "gid", va_arg (va, int));
     318           9 :                                 break;
     319             :                         case KEY_DIR:
     320        1415 :                                 mode |= KDB_DIR_MODE;
     321        1415 :                                 break;
     322             :                         case KEY_MODE:
     323          17 :                                 hasMode = 1;
     324          17 :                                 mode |= va_arg (va, int);
     325          17 :                                 break;
     326             :                         case KEY_ATIME:
     327           1 :                                 elektraSetMetaInt (key, "atime", va_arg (va, time_t));
     328           1 :                                 break;
     329             :                         case KEY_MTIME:
     330           1 :                                 elektraSetMetaInt (key, "mtime", va_arg (va, time_t));
     331           1 :                                 break;
     332             :                         case KEY_CTIME:
     333           1 :                                 elektraSetMetaInt (key, "ctime", va_arg (va, time_t));
     334           1 :                                 break;
     335             : 
     336             :                         default:
     337           0 :                                 ELEKTRA_ASSERT (0, "Unknown option " ELEKTRA_UNSIGNED_LONG_LONG_F " in keyVInit",
     338             :                                                 (kdb_unsigned_long_long_t) action);
     339             :                                 break;
     340             :                         }
     341             :                 }
     342             : 
     343     2213982 :                 option_t name_options = flags & (KEY_CASCADING_NAME | KEY_META_NAME | KEY_EMPTY_NAME);
     344     2213982 :                 elektraKeySetName (key, name, name_options);
     345             : 
     346     2213982 :                 if (!hasMode && mode == KDB_DIR_MODE)
     347        1410 :                         elektraSetMode (key, KDB_FILE_MODE | KDB_DIR_MODE);
     348     2212572 :                 else if (mode != 0)
     349          17 :                         elektraSetMode (key, mode);
     350             : 
     351     2213982 :                 if (owner) keySetOwner (key, owner);
     352             :         }
     353             : }

Generated by: LCOV version 1.13