Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Source for quickdump plugin
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 : #include "quickdump.h"
11 :
12 : #include <kdbendian.h>
13 : #include <kdbhelper.h>
14 :
15 : #include <kdberrors.h>
16 : #include <stdio.h>
17 :
18 : #define MAGIC_NUMBER_BASE (0x454b444200000000UL) // EKDB (in ASCII) + Version placeholder
19 :
20 : #define MAGIC_NUMBER_V1 ((kdb_unsigned_long_long_t) (MAGIC_NUMBER_BASE + 1))
21 : #define MAGIC_NUMBER_V2 ((kdb_unsigned_long_long_t) (MAGIC_NUMBER_BASE + 2))
22 : #define MAGIC_NUMBER_V3 ((kdb_unsigned_long_long_t) (MAGIC_NUMBER_BASE + 3))
23 :
24 : struct metaLink
25 : {
26 : const void * meta;
27 : size_t keyNameSize;
28 : const char * keyName;
29 : };
30 :
31 : struct list
32 : {
33 : size_t alloc;
34 : size_t size;
35 : struct metaLink ** array;
36 : };
37 :
38 : struct stringbuffer
39 : {
40 : size_t alloc;
41 : size_t offset;
42 : char * string;
43 : };
44 :
45 : static ssize_t findMetaLink (struct list * list, const Key * meta);
46 : static void insertMetaLink (struct list * list, size_t index, const Key * meta, Key * key, size_t parentOffset);
47 :
48 : static void setupBuffer (struct stringbuffer * buffer, size_t initialAlloc);
49 : static void ensureBufferSize (struct stringbuffer * buffer, size_t minSize);
50 :
51 : // keep #ifdef in sync with kdb export
52 : #ifdef _WIN32
53 : #define STDOUT_FILENAME ("CON")
54 : #else
55 : #define STDOUT_FILENAME ("/dev/stdout")
56 : #endif
57 :
58 : #include "varint.c"
59 :
60 1384 : static inline bool writeData (FILE * file, const char * data, kdb_unsigned_long_long_t size, Key * errorKey)
61 : {
62 1384 : if (!varintWrite (file, size))
63 : {
64 0 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (errorKey, feof (file) ? "Premature end of file" : "Unknown error");
65 0 : return false;
66 : }
67 :
68 1384 : if (size > 0)
69 : {
70 1238 : if (fwrite (data, sizeof (char), size, file) < size)
71 : {
72 0 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (errorKey, feof (file) ? "Premature end of file" : "Unknown error");
73 0 : return false;
74 : }
75 : }
76 : return true;
77 : }
78 :
79 : // for v1 and v2 reading
80 120 : static inline bool readUInt64 (FILE * file, kdb_unsigned_long_long_t * valuePtr, Key * errorKey)
81 : {
82 120 : if (fread (valuePtr, sizeof (kdb_unsigned_long_long_t), 1, file) < 1)
83 : {
84 0 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (errorKey, "Error while reading file");
85 0 : return false;
86 : }
87 : *valuePtr = le64toh (*valuePtr);
88 : return true;
89 : }
90 :
91 : // for v1 reading
92 58 : static inline char * readString (FILE * file, Key * errorKey)
93 : {
94 : kdb_unsigned_long_long_t size;
95 58 : if (!readUInt64 (file, &size, errorKey))
96 : {
97 0 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (errorKey, feof (file) ? "Premature end of file" : "Unknown error");
98 0 : return NULL;
99 : }
100 :
101 58 : char * string = elektraMalloc (size + 1);
102 58 : if (fread (string, sizeof (char), size, file) < size)
103 : {
104 0 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (errorKey, feof (file) ? "Premature end of file" : "Unknown error");
105 0 : elektraFree (string);
106 0 : return NULL;
107 : }
108 58 : string[size] = '\0';
109 58 : return string;
110 : }
111 :
112 : // for v2 reading
113 58 : static inline bool readStringIntoBufferV2 (FILE * file, struct stringbuffer * buffer, Key * errorKey)
114 : {
115 : kdb_unsigned_long_long_t size;
116 58 : if (!readUInt64 (file, &size, errorKey))
117 : {
118 0 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (errorKey, feof (file) ? "Premature end of file" : "Unknown error");
119 0 : return false;
120 : }
121 :
122 58 : size_t newSize = buffer->offset + size + 1;
123 58 : ensureBufferSize (buffer, newSize);
124 :
125 58 : if (fread (&buffer->string[buffer->offset], sizeof (char), size, file) < size)
126 : {
127 0 : ELEKTRA_SET_RESOURCE_ERROR (errorKey, feof (file) ? "Premature end of file" : "Unknown error");
128 0 : return false;
129 : }
130 58 : buffer->string[newSize - 1] = '\0';
131 58 : return true;
132 : }
133 :
134 : // for v3 reading
135 1370 : static inline bool readStringIntoBuffer (FILE * file, struct stringbuffer * buffer, Key * errorKey)
136 : {
137 1370 : kdb_unsigned_long_long_t size = 0;
138 1370 : if (!varintRead (file, &size))
139 : {
140 0 : ELEKTRA_SET_RESOURCE_ERROR (errorKey, feof (file) ? "Premature end of file" : "Unknown error");
141 0 : return false;
142 : }
143 :
144 1370 : size_t newSize = buffer->offset + size + 1;
145 1370 : ensureBufferSize (buffer, newSize);
146 :
147 1370 : if (fread (&buffer->string[buffer->offset], sizeof (char), size, file) < size)
148 : {
149 0 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (errorKey, feof (file) ? "Premature end of file" : "Unknown error");
150 0 : return false;
151 : }
152 1370 : buffer->string[newSize - 1] = '\0';
153 1370 : return true;
154 : }
155 :
156 : #include "readv1.c"
157 :
158 : #define readStringIntoBuffer readStringIntoBufferV2
159 : #include "readv2.c"
160 : #undef readStringIntoBuffer
161 :
162 358 : int elektraQuickdumpGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
163 : {
164 358 : if (!elektraStrCmp (keyName (parentKey), "system/elektra/modules/quickdump"))
165 : {
166 122 : KeySet * contract = ksNew (
167 : 30, keyNew ("system/elektra/modules/quickdump", KEY_VALUE, "quickdump plugin waits for your orders", KEY_END),
168 : keyNew ("system/elektra/modules/quickdump/exports", KEY_END),
169 : keyNew ("system/elektra/modules/quickdump/exports/get", KEY_FUNC, elektraQuickdumpGet, KEY_END),
170 : keyNew ("system/elektra/modules/quickdump/exports/set", KEY_FUNC, elektraQuickdumpSet, KEY_END),
171 : #include ELEKTRA_README
172 : keyNew ("system/elektra/modules/quickdump/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
173 122 : ksAppend (returned, contract);
174 122 : ksDel (contract);
175 :
176 122 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
177 : }
178 : // get all keys
179 :
180 236 : FILE * file = fopen (keyString (parentKey), "rb");
181 :
182 236 : if (file == NULL)
183 : {
184 0 : ELEKTRA_SET_ERROR_GET (parentKey);
185 : return ELEKTRA_PLUGIN_STATUS_ERROR;
186 : }
187 :
188 : kdb_unsigned_long_long_t magic;
189 236 : if (fread (&magic, sizeof (kdb_unsigned_long_long_t), 1, file) < 1)
190 : {
191 0 : if (feof (file) && ftell (file) == 0)
192 : {
193 0 : fclose (file);
194 0 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
195 : }
196 : else
197 : {
198 0 : fclose (file);
199 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
200 : }
201 : }
202 472 : magic = be64toh (magic); // magic number is written big endian so EKDB magic string is readable
203 :
204 236 : switch (magic)
205 : {
206 : case MAGIC_NUMBER_V1:
207 2 : return readVersion1 (file, returned, parentKey);
208 : case MAGIC_NUMBER_V2:
209 2 : return readVersion2 (file, returned, parentKey);
210 : case MAGIC_NUMBER_V3:
211 : // break, current version implemented below
212 : break;
213 : default:
214 0 : fclose (file);
215 0 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERRORF (parentKey, "Unknown magic number " ELEKTRA_UNSIGNED_LONG_LONG_F, magic);
216 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
217 : }
218 :
219 : // setup buffers
220 : struct stringbuffer valueBuffer;
221 232 : setupBuffer (&valueBuffer, 4);
222 :
223 : struct stringbuffer metaNameBuffer;
224 232 : setupBuffer (&metaNameBuffer, 4);
225 :
226 : // setup name buffer with parent key
227 : struct stringbuffer nameBuffer;
228 :
229 232 : size_t parentSize = keyGetNameSize (parentKey); // includes null terminator
230 464 : setupBuffer (&nameBuffer, parentSize + 4);
231 :
232 232 : keyGetName (parentKey, nameBuffer.string, parentSize);
233 232 : nameBuffer.string[parentSize - 1] = '/'; // replaces null terminator
234 232 : nameBuffer.string[parentSize] = '\0'; // set new null terminator
235 232 : nameBuffer.offset = parentSize; // set offset to null terminator
236 :
237 : char c;
238 863 : while ((c = fgetc (file)) != EOF)
239 : {
240 399 : ungetc (c, file);
241 :
242 399 : if (!readStringIntoBuffer (file, &nameBuffer, parentKey))
243 : {
244 0 : elektraFree (nameBuffer.string);
245 0 : elektraFree (metaNameBuffer.string);
246 0 : elektraFree (valueBuffer.string);
247 0 : fclose (file);
248 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
249 : }
250 :
251 399 : char type = fgetc (file);
252 399 : if (type == EOF)
253 : {
254 0 : elektraFree (nameBuffer.string);
255 0 : elektraFree (metaNameBuffer.string);
256 0 : elektraFree (valueBuffer.string);
257 0 : fclose (file);
258 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERROR (parentKey, "Missing key type");
259 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
260 : }
261 :
262 : Key * k;
263 :
264 399 : switch (type)
265 : {
266 : case 'b':
267 : {
268 : // binary key value
269 12 : kdb_unsigned_long_long_t valueSize = 0;
270 12 : if (!varintRead (file, &valueSize))
271 : {
272 0 : ELEKTRA_SET_RESOURCE_ERROR (parentKey, feof (file) ? "Premature end of file" : "Unknown error");
273 0 : elektraFree (nameBuffer.string);
274 0 : elektraFree (metaNameBuffer.string);
275 0 : elektraFree (valueBuffer.string);
276 0 : fclose (file);
277 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
278 : }
279 :
280 12 : if (valueSize == 0)
281 : {
282 2 : k = keyNew (nameBuffer.string, KEY_BINARY, KEY_SIZE, valueSize, KEY_END);
283 : }
284 : else
285 : {
286 10 : void * value = elektraMalloc (valueSize);
287 10 : if (fread (value, sizeof (char), valueSize, file) < valueSize)
288 : {
289 0 : elektraFree (nameBuffer.string);
290 0 : elektraFree (metaNameBuffer.string);
291 0 : fclose (file);
292 0 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (parentKey, "Error while reading file");
293 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
294 : }
295 10 : k = keyNew (nameBuffer.string, KEY_BINARY, KEY_SIZE, (size_t) valueSize, KEY_VALUE, value, KEY_END);
296 10 : elektraFree (value);
297 : }
298 12 : break;
299 : }
300 : case 's':
301 : {
302 : // string key value
303 387 : if (!readStringIntoBuffer (file, &valueBuffer, parentKey))
304 : {
305 0 : elektraFree (nameBuffer.string);
306 0 : elektraFree (metaNameBuffer.string);
307 0 : elektraFree (valueBuffer.string);
308 0 : fclose (file);
309 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
310 : }
311 387 : k = keyNew (nameBuffer.string, KEY_VALUE, valueBuffer.string, KEY_END);
312 387 : break;
313 : }
314 : default:
315 0 : elektraFree (nameBuffer.string);
316 0 : elektraFree (metaNameBuffer.string);
317 0 : elektraFree (valueBuffer.string);
318 0 : fclose (file);
319 0 : ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Unknown key type %c", type);
320 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
321 : }
322 :
323 691 : while ((c = fgetc (file)) != 0)
324 : {
325 292 : if (c == EOF)
326 : {
327 0 : keyDel (k);
328 0 : fclose (file);
329 0 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERROR (parentKey, "Missing key end");
330 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
331 : }
332 :
333 292 : switch (c)
334 : {
335 : case 'm':
336 : {
337 : // meta key
338 285 : if (!readStringIntoBuffer (file, &metaNameBuffer, parentKey))
339 : {
340 0 : keyDel (k);
341 0 : elektraFree (nameBuffer.string);
342 0 : elektraFree (metaNameBuffer.string);
343 0 : elektraFree (valueBuffer.string);
344 0 : fclose (file);
345 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
346 : }
347 :
348 285 : if (!readStringIntoBuffer (file, &valueBuffer, parentKey))
349 : {
350 0 : keyDel (k);
351 0 : elektraFree (nameBuffer.string);
352 0 : elektraFree (metaNameBuffer.string);
353 0 : elektraFree (valueBuffer.string);
354 0 : fclose (file);
355 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
356 : }
357 285 : const char * metaValue = valueBuffer.string;
358 :
359 285 : keySetMeta (k, metaNameBuffer.string, metaValue);
360 285 : break;
361 : }
362 : case 'c':
363 : {
364 : // copy meta
365 7 : if (!readStringIntoBuffer (file, &nameBuffer, parentKey))
366 : {
367 0 : keyDel (k);
368 0 : elektraFree (nameBuffer.string);
369 0 : elektraFree (metaNameBuffer.string);
370 0 : elektraFree (valueBuffer.string);
371 0 : fclose (file);
372 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
373 : }
374 :
375 7 : if (!readStringIntoBuffer (file, &metaNameBuffer, parentKey))
376 : {
377 0 : keyDel (k);
378 0 : elektraFree (nameBuffer.string);
379 0 : elektraFree (metaNameBuffer.string);
380 0 : elektraFree (valueBuffer.string);
381 0 : fclose (file);
382 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
383 : }
384 :
385 7 : const Key * sourceKey = ksLookupByName (returned, nameBuffer.string, 0);
386 7 : if (sourceKey == NULL)
387 : {
388 0 : ELEKTRA_SET_RESOURCE_ERRORF (parentKey, "Could not copy meta data from key '%s': Key not found",
389 : nameBuffer.string);
390 0 : keyDel (k);
391 0 : elektraFree (nameBuffer.string);
392 0 : elektraFree (metaNameBuffer.string);
393 0 : elektraFree (valueBuffer.string);
394 0 : fclose (file);
395 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
396 : }
397 :
398 7 : if (keyCopyMeta (k, sourceKey, metaNameBuffer.string) != 1)
399 : {
400 0 : ELEKTRA_SET_INTERNAL_ERRORF (parentKey, "Could not copy meta data from key '%s': Error during copy",
401 : &nameBuffer.string[nameBuffer.offset]);
402 0 : keyDel (k);
403 0 : elektraFree (nameBuffer.string);
404 0 : elektraFree (metaNameBuffer.string);
405 0 : elektraFree (valueBuffer.string);
406 0 : fclose (file);
407 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
408 : }
409 : break;
410 : }
411 : default:
412 0 : keyDel (k);
413 0 : elektraFree (nameBuffer.string);
414 0 : elektraFree (metaNameBuffer.string);
415 0 : elektraFree (valueBuffer.string);
416 0 : fclose (file);
417 0 : ELEKTRA_SET_VALIDATION_SYNTACTIC_ERRORF (parentKey, "Unknown meta type %c", type);
418 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
419 : }
420 : }
421 :
422 399 : ksAppendKey (returned, k);
423 : }
424 :
425 232 : elektraFree (nameBuffer.string);
426 232 : elektraFree (metaNameBuffer.string);
427 232 : elektraFree (valueBuffer.string);
428 :
429 232 : fclose (file);
430 :
431 232 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
432 : }
433 :
434 235 : int elektraQuickdumpSet (Plugin * handle, KeySet * returned, Key * parentKey)
435 : {
436 235 : cursor_t cursor = ksGetCursor (returned);
437 235 : ksRewind (returned);
438 :
439 : FILE * file;
440 :
441 : // cannot open stdout for writing, because its already open
442 235 : if (elektraStrCmp (keyString (parentKey), STDOUT_FILENAME) == 0)
443 : {
444 46 : file = stdout;
445 : }
446 : else
447 : {
448 189 : file = fopen (keyString (parentKey), "wb");
449 : }
450 :
451 235 : if (file == NULL)
452 : {
453 0 : ELEKTRA_SET_ERROR_SET (parentKey);
454 : return ELEKTRA_PLUGIN_STATUS_ERROR;
455 : }
456 :
457 : // magic number is written big endian so EKDB magic string is readable
458 235 : kdb_unsigned_long_long_t magic = htobe64 (MAGIC_NUMBER_V3);
459 235 : if (fwrite (&magic, sizeof (kdb_unsigned_long_long_t), 1, file) < 1)
460 : {
461 0 : fclose (file);
462 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
463 : }
464 :
465 : struct list metaKeys;
466 235 : metaKeys.alloc = 16;
467 235 : metaKeys.size = 0;
468 235 : metaKeys.array = elektraMalloc (metaKeys.alloc * sizeof (struct metaLink *));
469 :
470 : // we assume all keys in returned are below parentKey
471 235 : size_t parentOffset = keyGetNameSize (parentKey);
472 :
473 : // ... unless /noparent is in config, then we just take the full
474 : // (cascading) keynames as relative to the parentKey
475 235 : KeySet * config = elektraPluginGetConfig (handle);
476 235 : if (ksLookupByName (config, "/noparent", 0) != NULL)
477 : {
478 6 : parentOffset = 1;
479 : }
480 :
481 : Key * cur;
482 629 : while ((cur = ksNext (returned)) != NULL)
483 : {
484 394 : size_t fullNameSize = keyGetNameSize (cur);
485 394 : if (fullNameSize < parentOffset)
486 : {
487 0 : fclose (file);
488 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
489 : }
490 :
491 394 : kdb_unsigned_long_long_t nameSize = fullNameSize == parentOffset ? 0 : fullNameSize - 1 - parentOffset;
492 394 : if (!writeData (file, keyName (cur) + parentOffset, nameSize, parentKey))
493 : {
494 0 : fclose (file);
495 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
496 : }
497 :
498 394 : if (keyIsBinary (cur))
499 : {
500 16 : if (fputc ('b', file) == EOF)
501 : {
502 0 : fclose (file);
503 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
504 : }
505 :
506 16 : kdb_unsigned_long_long_t valueSize = keyGetValueSize (cur);
507 :
508 16 : char * value = NULL;
509 16 : if (valueSize > 0)
510 : {
511 10 : value = elektraMalloc (valueSize);
512 10 : if (keyGetBinary (cur, value, valueSize) == -1)
513 : {
514 0 : fclose (file);
515 0 : elektraFree (value);
516 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
517 : }
518 : }
519 :
520 16 : if (!writeData (file, value, valueSize, parentKey))
521 : {
522 0 : fclose (file);
523 0 : elektraFree (value);
524 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
525 : }
526 16 : elektraFree (value);
527 : }
528 : else
529 : {
530 378 : if (fputc ('s', file) == EOF)
531 : {
532 0 : fclose (file);
533 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
534 : }
535 :
536 378 : kdb_unsigned_long_long_t valueSize = keyGetValueSize (cur) - 1;
537 378 : if (!writeData (file, keyString (cur), valueSize, parentKey))
538 : {
539 0 : fclose (file);
540 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
541 : }
542 : }
543 :
544 394 : keyRewindMeta (cur);
545 : const Key * meta;
546 1086 : while ((meta = keyNextMeta (cur)) != NULL)
547 : {
548 298 : ssize_t result = findMetaLink (&metaKeys, meta);
549 298 : if (result < 0)
550 : {
551 292 : if (fputc ('m', file) == EOF)
552 : {
553 0 : fclose (file);
554 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
555 : }
556 :
557 292 : kdb_unsigned_long_long_t metaNameSize = keyGetNameSize (meta) - 1;
558 292 : if (!writeData (file, keyName (meta), metaNameSize, parentKey))
559 : {
560 0 : fclose (file);
561 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
562 : }
563 :
564 292 : kdb_unsigned_long_long_t metaValueSize = keyGetValueSize (meta) - 1;
565 292 : if (!writeData (file, keyString (meta), metaValueSize, parentKey))
566 : {
567 0 : fclose (file);
568 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
569 : }
570 :
571 292 : insertMetaLink (&metaKeys, -result - 1, meta, cur, parentOffset);
572 : }
573 : else
574 : {
575 6 : if (fputc ('c', file) == EOF)
576 : {
577 0 : fclose (file);
578 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
579 : }
580 :
581 6 : kdb_unsigned_long_long_t keyNameSize = metaKeys.array[result]->keyNameSize;
582 6 : if (!writeData (file, metaKeys.array[result]->keyName, keyNameSize, parentKey))
583 : {
584 0 : fclose (file);
585 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
586 : }
587 :
588 6 : kdb_unsigned_long_long_t metaNameSize = keyGetNameSize (meta) - 1;
589 6 : if (!writeData (file, keyName (meta), metaNameSize, parentKey))
590 : {
591 0 : fclose (file);
592 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
593 : }
594 : }
595 : }
596 :
597 394 : if (fputc (0, file) == EOF)
598 : {
599 0 : fclose (file);
600 0 : return ELEKTRA_PLUGIN_STATUS_ERROR;
601 : }
602 : }
603 :
604 292 : for (size_t i = 0; i < metaKeys.size; ++i)
605 : {
606 292 : elektraFree (metaKeys.array[i]);
607 : }
608 235 : elektraFree (metaKeys.array);
609 :
610 235 : fclose (file);
611 :
612 235 : ksSetCursor (returned, cursor);
613 :
614 235 : return ELEKTRA_PLUGIN_STATUS_SUCCESS;
615 : }
616 :
617 298 : ssize_t findMetaLink (struct list * list, const Key * meta)
618 : {
619 298 : const void * search = meta;
620 :
621 298 : if (list->size == 0)
622 : {
623 : return -1;
624 : }
625 :
626 164 : if (search > list->array[list->size - 1]->meta)
627 : {
628 72 : return -(ssize_t) list->size - 1;
629 : }
630 :
631 92 : ssize_t left = 0;
632 92 : ssize_t right = list->size;
633 92 : --right;
634 :
635 92 : ssize_t insertpos = 0;
636 :
637 223 : while (left <= right)
638 : {
639 137 : size_t middle = left + ((right - left) / 2);
640 :
641 137 : if (list->array[middle]->meta < search)
642 : {
643 30 : insertpos = left = middle + 1;
644 : }
645 107 : else if (list->array[middle]->meta == search)
646 : {
647 : return middle;
648 : }
649 : else
650 : {
651 101 : insertpos = middle;
652 101 : right = middle - 1;
653 : }
654 : }
655 :
656 86 : return -insertpos - 1;
657 : }
658 :
659 292 : void insertMetaLink (struct list * list, size_t index, const Key * meta, Key * key, size_t parentOffset)
660 : {
661 292 : if (list->size + 1 >= list->alloc)
662 : {
663 0 : list->alloc *= 2;
664 0 : elektraRealloc ((void **) &list->array, sizeof (struct metaLink *) * list->alloc);
665 : }
666 :
667 292 : struct metaLink * link = elektraMalloc (sizeof (struct metaLink));
668 292 : link->meta = meta;
669 292 : size_t fullNameSize = keyGetNameSize (key);
670 292 : link->keyNameSize = fullNameSize <= parentOffset ? 0 : fullNameSize - 1 - parentOffset;
671 292 : link->keyName = keyName (key) + parentOffset;
672 :
673 292 : if (index < list->size)
674 : {
675 86 : memmove (&list->array[index + 1], &list->array[index], (list->size - index) * sizeof (struct metaLink *));
676 : }
677 :
678 292 : list->array[index] = link;
679 292 : ++list->size;
680 292 : }
681 :
682 : void setupBuffer (struct stringbuffer * buffer, size_t initialAlloc)
683 : {
684 702 : buffer->offset = 0;
685 702 : buffer->alloc = initialAlloc;
686 702 : buffer->string = elektraMalloc (initialAlloc * sizeof (char));
687 : }
688 :
689 : void ensureBufferSize (struct stringbuffer * buffer, size_t minSize)
690 : {
691 1428 : size_t alloc = buffer->alloc;
692 2082 : while (alloc < minSize)
693 : {
694 654 : alloc *= 2;
695 : }
696 :
697 1428 : if (alloc != buffer->alloc)
698 : {
699 479 : elektraRealloc ((void **) &buffer->string, alloc);
700 479 : buffer->alloc = alloc;
701 : }
702 : }
703 :
704 324 : Plugin * ELEKTRA_PLUGIN_EXPORT
705 : {
706 : // clang-format off
707 324 : return elektraPluginExport ("quickdump",
708 : ELEKTRA_PLUGIN_GET, &elektraQuickdumpGet,
709 : ELEKTRA_PLUGIN_SET, &elektraQuickdumpSet,
710 : ELEKTRA_PLUGIN_END);
711 : // clang-format on
712 : }
|