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 : }
|