Git init
[pkgs/e/elektra.git] / src / libelektra / keyhelpers.c
1 /***************************************************************************
2                           keyhelpers.c  -  Methods for Key manipulation
3                              -------------------
4     begin                : Mon Dec 29 2003
5     copyright            : (C) 2003 by Avi Alkalay
6     email                : avi@unix.sh
7  ***************************************************************************/
8
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the BSD License (revised).                      *
13  *                                                                         *
14  ***************************************************************************/
15
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19
20 #if DEBUG && HAVE_STDIO_H
21 #include <stdio.h>
22 #endif
23
24 #ifdef HAVE_STDARG_H
25 #include <stdarg.h>
26 #endif
27
28 #ifdef HAVE_STRING_H
29 #include <string.h>
30 #endif
31
32 #ifdef HAVE_STDLIB_H
33 #include <stdlib.h>
34 #endif
35
36 #include "kdb.h"
37 #include "kdbprivate.h"
38
39
40
41 /*
42  * Returns one level of the key name.
43  *
44  * This method is used to skip repeating '/' and to find escaping chars.
45  * Given @p keyName, this method returns a pointer to the next name level
46  * found and changes @p size to the number of bytes on this level name.
47  *
48  * This method is used by keySetName() to cleanup parameters
49  * before being accepted in the Key object.
50  *
51  * @code
52 // Lets define a key name with a lot of repeating '/' and escaped '/'
53 char *keyName="user////abc/def\/ghi////jkl///";
54 char *p;
55 size_t size=0;
56 int level=0;
57 char buffer[20];
58
59 p=keyName;
60 while (*(p=keyNameGetOneLevel(p+size,&size))) {
61         level++;
62
63         // copy what we found to a buffer, so we can NULL-terminate it
64         strncpy(buffer,p,size);
65         buffer[size]=0;
66
67         printf("Level %d name: \"%s\"\n",level,buffer);
68 }
69
70  * The above example will produce the following output:
71  *
72  * @code
73 Level 1 name: user
74 Level 2 name: abc
75 Level 3 name: def\/ghi
76 Level 4 name: jkl
77  * @endcode
78  *
79  * @param name the string that will be searched
80  * @param size the number of bytes of level name found in @p keyName until
81  *      the next delimiter ('/')
82  * @return a pointer to the first char of the next level name, it will point to
83  *      NULL when done.
84  * @ingroup keyname
85  */
86 char *keyNameGetOneLevel(const char *name, size_t *size) {
87         char *real=(char *)name;
88         size_t cursor=0;
89         int escapeNext=0;
90         int end=0;
91         
92         /* skip all repeating '/' in the begining */
93         while (*real && *real == PATH_SEPARATOR) real++;
94         
95         /* now see where this basename ends handling escaped chars with '\' */
96         while (real[cursor] && ! end) {
97                 switch (real[cursor]) {
98                         case '\\':
99                                 escapeNext=1;
100                                 break;
101                         case PATH_SEPARATOR:
102                                 if (! escapeNext) end=1;
103                         default:
104                                 escapeNext=0;
105                 }
106                 ++cursor;
107         }
108         
109         /* if a '/' stopped our loop, balance the counter */
110         if (end) --cursor;
111         
112         *size=cursor;
113         return real;
114 }
115
116
117
118
119 /*
120  * Gets number of bytes needed to store root name of a key name
121  *
122  * Possible root key names are @p system, @p user or @p "user:someuser" .
123  *
124  * @return number of bytes needed with ending NULL
125  * @param keyName the name of the key
126  * @see keyGetFullRootNameSize()
127  * @ingroup keyname
128  */
129 ssize_t keyNameGetFullRootNameSize(const char *keyName) {
130         char *end;
131         int length=strlen(keyName);
132
133         if (!length) return 0;
134
135         /*
136                 Possible situations:
137                 user:someuser
138                 user:someuser/
139                 user:someuser/key/name
140                 user:some.user/key/name
141                 .
142                 \.
143                 (empty)
144         */
145         end=strchr(keyName,PATH_SEPARATOR);
146         if (!end) /* Reached end of string. Root is entire key. */
147                 end = (char *)keyName + length;
148
149         return end-keyName+1;
150 }
151
152
153
154 /*
155  * Gets number of bytes needed to store root name of a key.
156  *
157  * Possible root key names are @p system or @p user .
158  * This method does not consider the user domain in @p user:username keys.
159  *
160  * @param key the key object to work with
161  * @return number of bytes needed with the ending NULL
162  * @see keyGetFullRootNameSize()
163  * @ingroup keyname
164  */
165 ssize_t keyGetRootNameSize(const Key *key) {
166         if (!key->key) return 0;
167
168         if (keyIsUser(key)) return sizeof("db");
169         else if (keyIsSystem(key)) return sizeof("file");
170         else return sizeof("memory");
171 }
172
173
174
175 /*
176  * Copy to @p returned the root name of @p key.
177  *
178  * Some examples:
179  * - root of @p system/some/key is @p system
180  * - root of @p user:denise/some/key is @p user
181  * - root of @p user/env/env1 is @p user
182  *
183  * Use keyGetFullRootName() to get also the user domain.
184  *
185  * @param key the key to extract root from
186  * @param returned a pre-allocated buffer to store the rootname
187  * @param maxSize size of the @p returned buffer
188  * @return number of bytes needed with ending NULL
189  * @see keyGetRootNameSize(), keyGetFullRootName()
190  * @ingroup keyname
191  */
192 ssize_t keyGetRootName(const Key *key, char *returned, size_t maxSize) {
193         size_t size;
194
195         if (!key->key) {
196                 /*errno=KDB_ERR_NOKEY;*/
197                 return -1;
198         }
199
200         if (!(size=keyGetRootNameSize(key))) {
201                 /*errno=KDB_ERR_NOKEY;*/
202                 return -1;
203         }
204
205         if (maxSize < size) {
206                 /*errno=KDB_ERR_TRUNC;*/
207                 return -1;
208         } else strncpy(returned,key->key,size-1);
209         returned[size-1]=0; /* null terminate it */
210         return size;
211 }
212
213
214
215
216
217
218 /*
219  * Gets number of bytes needed to store root name of a key name without
220  * user domain.
221  *
222  * Some examples:
223  * - root of @p system/some/key is @p system
224  * - root of @p user:denise/some/key is @p user
225  * - root of @p user/env/env1 is @p user
226  *
227  * @param keyName the name of the key
228  * @return number of bytes needed with ending NULL or -1 if @p keyName is
229  *      not a valid name and @c errno is set to KDBErr::KDB_ERR_INVALIDKEY
230  * @see keyGetRootNameSize()
231  * @ingroup keyname
232  */
233 ssize_t keyNameGetRootNameSize(const char *keyName) {
234         int length=strlen(keyName);
235
236         if (!length) return 0;
237
238         /*
239                 Possible situations:
240         user
241         user/
242         user/blabla
243         user:someuser
244         user:someuser/
245         user:someuser/key/name
246         system
247         system/
248         system/blabla
249         (empty)
250         */
251         
252         if (keyNameIsUser(keyName)) return sizeof("db");
253         else if (keyNameIsSystem(keyName)) return sizeof("file");
254         else if (keyNameIsMemory(keyName)) return sizeof("memory");
255         else {
256                 /*errno=KDB_ERR_INVALIDKEY;*/
257                 return -1;
258         }
259 }
260
261
262
263
264
265 /*
266  * Calculates number of bytes needed to store full root name of a key.
267  *
268  * Possible root key names are @p system, @p user or @p user:someuser.
269  * In contrast to keyGetRootNameSize(), this method considers the user
270  * domain part, and you should prefer this one.
271  *
272  * @param key the key object to work with
273  * @return number of bytes needed with ending NULL
274  * @see keyGetRootNameSize()
275  * @ingroup keyname
276  */
277 ssize_t keyGetFullRootNameSize(const Key *key) {
278         size_t size=0;
279
280         if (keyIsUser(key)) {
281                 if (key->owner) size=kdbiStrLen(key->owner);
282                 
283                 return size+sizeof("db");
284         } else {
285                 return keyNameGetRootNameSize(key->key);
286         }
287 }
288
289
290 /*
291  * Copy to @p returned the full root name of the key.
292  *
293  * Some examples:
294  * - root of @p system/some/key is @p system
295  * - root of @p user:denise/some/key is @p user:denise
296  * - root of @p user/env/env1 is @p user:$USER
297  *
298  * This method is more robust then keyGetRootName()
299  *
300  * @param key the key to extract root from
301  * @param returned a pre-allocated buffer to store the rootname
302  * @param maxSize size of the @p returned buffer
303  * @return number of bytes written to @p returned including ending NULL
304  * @see keyGetFullRootNameSize(), keyGetRootName()
305  * @ingroup keyname
306  */
307 ssize_t keyGetFullRootName(const Key *key, char *returned, size_t maxSize) {
308         size_t size;
309         size_t rootSize;
310         char *cursor;
311
312         if (!key->key) {
313                 /*errno=KDB_ERR_NOKEY;*/
314                 return 0;
315         }
316
317         if (!(size=keyGetFullRootNameSize(key))) {
318                 /*errno=KDB_ERR_NOKEY;*/
319                 return 0;
320         }
321
322         if (maxSize < size) {
323                 /*errno=KDB_ERR_TRUNC;*/
324                 return -1;
325         }
326         
327         rootSize = keyGetRootNameSize(key)-1;
328         strncpy(returned,key->key, rootSize); /* copy "user" or "system" */
329         if (keyIsUser(key)) {
330                 cursor = returned + rootSize;
331                 *cursor = ':'; cursor++;
332                 if (key->owner)
333                 {
334                         strncpy (cursor, key->owner, size - rootSize - 1); /* -1 for : */
335                 }
336         } else {
337                 returned[rootSize]=0;
338         }
339
340         return size;
341 }
342
343
344
345
346
347
348 /*
349  * Get the number of bytes needed to store this key's parent name without
350  * user domain, and with the ending NULL.
351  *
352  * @param key the key object to work with
353  * @see keyGetParentName() for example
354  * @ingroup keyname
355  */
356 ssize_t keyGetParentNameSize(const Key *key) {
357         char *parentNameEnd=0;
358         char *p;
359         size_t size;
360
361         if (!key->key) {
362                 /*errno=KDB_ERR_NOKEY;*/
363                 return 0;
364         }
365
366         /*
367                 user   (size=0)
368                 user/parent/base       (size=sizeof("user/parent"))
369                 user/parent/base/      (size=sizeof("user/parent"))
370                 user/parent/base\/name (size=sizeof("user/parent"))
371         */
372
373         /* initialize */
374         p=key->key;
375         size=0;
376         
377         /* iterate over level names */
378         while (*(p=keyNameGetOneLevel(p+size,&size))) parentNameEnd=p;
379         
380         /* handle NULL or root key ("user" or "system") */
381         if (!parentNameEnd || parentNameEnd==key->key) return 0;
382
383         /* at this point, parentNameEnd points to the first char of the basename */
384         /* example: it points to the 'b' of "user/key/basename" */
385         
386         /* the delta is the size we want */
387         return parentNameEnd - key->key;
388 }
389
390
391
392 /*
393  * Copy this key's parent name (without owner) into a pre-allocated buffer.
394  *
395  * @par Example:
396  * @code
397 Key *key=keyNew("system/parent/base",KEY_SWITCH_END);
398 char *parentName;
399 size_t parentSize;
400
401 parentSize=keyGetParentNameSize(key);
402 parentName=malloc(parentSize);
403 keyGetParentName(key,parentName,parentSize);
404 // work with parentName
405 free (parentName);
406  * @endcode
407  * @see keyGetParentNameSize()
408  * @param key the key object to work with
409  * @param returnedParent pre-allocated buffer to copy parent name to
410  * @param maxSize number of bytes pre-allocated
411  * @return number of bytes copied including ending NULL
412  * @ingroup keyname
413  */
414 ssize_t keyGetParentName(const Key *key, char *returnedParent, size_t maxSize) {
415         ssize_t parentSize;
416
417         parentSize=keyGetParentNameSize(key);
418
419         if (parentSize > maxSize) {
420                 /*errno=KDB_ERR_TRUNC;*/
421                 return 0;
422         } else strncpy(returnedParent,key->key,parentSize);
423
424         returnedParent[parentSize-1]=0; /* ending NULL */
425         
426         return parentSize;
427 }
428
429
430
431
432 /*
433  * Return the namespace of a key name.
434  *
435  * Currently valid namespaces are KeyNamespace::KEY_NS_SYSTEM and KeyNamespace::KEY_NS_USER.
436  *
437  * @param keyName the name to deduce the namespace from
438  * @return KeyNamespace::KEY_NS_SYSTEM, KeyNamespace::KEY_NS_USER
439  * @return 0 for no valid namespace found (key has no name)
440  * @see keyGetNamespace(), keyIsUser(), keyIsSystem()
441  * @see #KeyNamespace
442  * @ingroup keytest
443  *
444  */
445 int keyNameGetNamespace(const char *keyName)
446 {
447         if (keyNameIsSystem(keyName)) return KEY_NS_SYSTEM;
448         if (keyNameIsUser(keyName)) return KEY_NS_USER;
449         if (keyNameIsMemory(keyName)) return KEY_NS_MEMORY;
450         return 0;
451 }
452
453
454
455 /*
456  * Return the namespace of a key
457  *
458  * Currently valid namespaces are KeyNamespace::KEY_NS_SYSTEM and KeyNamespace::KEY_NS_USER.
459  *
460  * @param key the key object to work with
461  * @return 0
462  * @see keyIsUser(), keyIsSystem()
463  * @ingroup keytest
464  *
465  */
466 int keyGetNamespace(const Key *key)
467 {
468         if (keyIsUser (key)) return KEY_NS_USER;
469         else if (keyIsSystem (key)) return KEY_NS_SYSTEM;
470         else if (keyIsMemory(key)) return KEY_NS_MEMORY;
471         else return 0;
472 }
473
474
475 /*
476  * Check whether a key name is under the @p system namespace or not
477  *
478  * @return 1 if string begins with @p system , 0 otherwise
479  * @param keyName the name of a key
480  * @see keyIsSystem(), keyIsUser(), keyNameIsUser()
481  * @ingroup keyname
482  *
483  */
484 int keyNameIsSystem(const char *keyName)
485 {
486         if (!strncmp("file",keyName,sizeof("file")-1)) return 1;
487         return 0;
488 }
489
490
491 /*
492  * Check whether a key name is under the @p user namespace or not
493  *
494  * @return 1 if string begins with @p user, 0 otherwise
495  * @param keyName the name of a key
496  * @see keyIsSystem(), keyIsUser(), keyNameIsSystem()
497  * @ingroup keyname
498  *
499  */
500 int keyNameIsUser(const char *keyName)
501 {
502         if (!strncmp("db",keyName,sizeof("db")-1)) return 1;
503         return 0;
504 }
505
506
507 /*
508  * Check whether a key name is under the @p memory namespace or not
509  *
510  * @return 1 if string begins with @p user, 0 otherwise
511  * @param keyName the name of a key
512  * @see keyIsSystem(), keyIsUser(), keyNameIsSystem()
513  * @ingroup keyname
514  *
515  */
516 int keyNameIsMemory(const char *keyName)
517 {
518         if (!strncmp("memory",keyName,sizeof("memory")-1)) return 1;
519         return 0;
520 }
521
522
523 /*********************************************************************
524  *                Data constructors (protected)                      *
525  *********************************************************************/
526 int keyInit(Key *key)
527 {
528         memset(key,0,sizeof(Key));
529
530         key->type = KEY_TYPE_UNDEFINED;
531
532         key->uid = (uid_t)-1;
533         key->gid = (gid_t)-1;
534
535         key->mode = KEY_DEF_MODE;
536         return 0;
537 }
538