LCOV - code coverage report
Current view: top level - src/plugins/quickdump - quickdump.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 180 325 55.4 %
Date: 2019-09-12 12:28:41 Functions: 10 12 83.3 %

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

Generated by: LCOV version 1.13