LCOV - code coverage report
Current view: top level - src/plugins/file - file.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 81 102 79.4 %
Date: 2019-09-12 12:28:41 Functions: 3 4 75.0 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief Source for file plugin
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  *
       8             :  */
       9             : 
      10             : #include "file.h"
      11             : #include <fcntl.h>
      12             : #include <kdberrors.h>
      13             : #include <kdbhelper.h>
      14             : #include <stdio.h>
      15             : #include <stdlib.h>
      16             : #include <string.h>
      17             : #include <sys/stat.h>
      18             : #include <time.h>
      19             : 
      20             : 
      21          40 : int elektraFileGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned ELEKTRA_UNUSED, Key * parentKey ELEKTRA_UNUSED)
      22             : {
      23          40 :         if (!elektraStrCmp (keyName (parentKey), "system/elektra/modules/file"))
      24             :         {
      25          31 :                 KeySet * contract =
      26          31 :                         ksNew (30, keyNew ("system/elektra/modules/file", KEY_VALUE, "file plugin waits for your orders", KEY_END),
      27             :                                keyNew ("system/elektra/modules/file/exports", KEY_END),
      28             :                                keyNew ("system/elektra/modules/file/exports/get", KEY_FUNC, elektraFileGet, KEY_END),
      29             :                                keyNew ("system/elektra/modules/file/exports/set", KEY_FUNC, elektraFileSet, KEY_END),
      30             : #include ELEKTRA_README
      31             :                                keyNew ("system/elektra/modules/file/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
      32          31 :                 ksAppend (returned, contract);
      33          31 :                 ksDel (contract);
      34             : 
      35          31 :                 return 1; // success
      36             :         }
      37             : 
      38           9 :         short binary = 0;
      39           9 :         short info = 0;
      40           9 :         KeySet * config = elektraPluginGetConfig (handle);
      41           9 :         Key * lookup = ksLookupByName (config, "/info", KDB_O_NONE);
      42           9 :         if (lookup) info = 1;
      43           9 :         lookup = ksLookupByName (config, "/binary", KDB_O_NONE);
      44           9 :         if (lookup) binary = 1;
      45             : 
      46           9 :         const char * fileName = keyString (parentKey);
      47             : 
      48             :         struct stat sb;
      49           9 :         if (stat (fileName, &sb) == -1)
      50             :         {
      51           0 :                 ELEKTRA_SET_RESOURCE_ERRORF (parentKey, "Failed to stat file %s, aborting. Reason: %s", fileName, strerror (errno));
      52           0 :                 return -1;
      53             :         }
      54             : 
      55           9 :         long long fileSize = (long long) sb.st_size;
      56             : 
      57           9 :         unsigned char * buffer = NULL;
      58           9 :         if (!binary)
      59           9 :                 buffer = elektraMalloc (fileSize + 1); // fileSize + null terminator
      60             :         else
      61           0 :                 buffer = elektraMalloc (fileSize);
      62             : 
      63           9 :         if (!buffer)
      64             :         {
      65           0 :                 ELEKTRA_SET_OUT_OF_MEMORY_ERRORF (parentKey, "Failed to allocate buffer of %lld bytes for %s", fileSize, fileName);
      66           0 :                 return -1;
      67             :         }
      68             : 
      69           9 :         FILE * fp = NULL;
      70           9 :         fp = fopen (fileName, "rb");
      71           9 :         if (!fp)
      72             :         {
      73           0 :                 ELEKTRA_SET_RESOURCE_ERRORF (parentKey, "Failed to open file %s. Reason: %s", fileName, strerror (errno));
      74           0 :                 elektraFree (buffer);
      75           0 :                 return -1;
      76             :         }
      77             : 
      78             : 
      79             :         // loop until until fileSize elements of size sizeof(char) are read
      80             :         long long bytesRead = 0;
      81          18 :         while (bytesRead < fileSize)
      82             :         {
      83           9 :                 size_t bytes = fread (buffer + bytesRead, 1, (size_t) fileSize, fp);
      84           9 :                 if (bytes == 0) break;
      85           9 :                 bytesRead += bytes;
      86             :         }
      87             : 
      88           9 :         if (bytesRead < fileSize)
      89             :         {
      90           0 :                 ELEKTRA_SET_VALIDATION_SYNTACTIC_ERRORF (parentKey, "Failed to read %s completely. Got %lld of %lld bytes", fileName,
      91             :                                                          bytesRead, fileSize);
      92           0 :                 elektraFree (buffer);
      93           0 :                 fclose (fp);
      94           0 :                 return -1;
      95             :         }
      96           9 :         fclose (fp);
      97             : 
      98           9 :         Key * key = keyNew (keyName (parentKey), KEY_END);
      99           9 :         if (binary)
     100             :         {
     101           0 :                 keySetBinary (key, (const void *) buffer, (size_t) fileSize);
     102             :         }
     103             :         else
     104             :         {
     105           9 :                 buffer[fileSize] = '\0';
     106           9 :                 keySetString (key, (char *) buffer);
     107             :         }
     108           9 :         if (info)
     109           3 :         {
     110           3 :                 unsigned long long maxValue = UINT64_MAX;
     111           3 :                 size_t maxChars = snprintf (NULL, 0, "%llu", maxValue);
     112           3 :                 char tmp[maxChars + 1]; //
     113           3 :                 snprintf (tmp, sizeof (tmp), "%lld", fileSize);
     114           3 :                 keySetMeta (key, "info/size", tmp);
     115           3 :                 keySetMeta (key, "info/ctime", ctime (&sb.st_ctime));
     116           3 :                 keySetMeta (key, "info/atime", ctime (&sb.st_atime));
     117           3 :                 keySetMeta (key, "info/mtime", ctime (&sb.st_mtime));
     118           3 :                 snprintf (tmp, sizeof (tmp), "%ld", (long) sb.st_uid);
     119           3 :                 keySetMeta (key, "info/uid", tmp);
     120           3 :                 snprintf (tmp, sizeof (tmp), "%ld", (long) sb.st_gid);
     121           3 :                 keySetMeta (key, "info/gid", tmp);
     122           3 :                 snprintf (tmp, sizeof (tmp), "%o", (unsigned int) sb.st_mode);
     123           3 :                 keySetMeta (key, "info/mode", tmp);
     124           3 :                 snprintf (tmp, sizeof (tmp), "%ld", (long) sb.st_ino);
     125           3 :                 keySetMeta (key, "info/inode", tmp);
     126             :         }
     127           9 :         ksAppendKey (returned, key);
     128             : 
     129           9 :         elektraFree (buffer);
     130           9 :         return 1; // success
     131             : }
     132             : 
     133           6 : int elektraFileSet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned ELEKTRA_UNUSED, Key * parentKey ELEKTRA_UNUSED)
     134             : {
     135             :         // set all keys
     136             :         // this function is optional
     137           6 :         const Key * key = ksLookup (returned, parentKey, KDB_O_NONE);
     138           6 :         if (!key) return 0;
     139           6 :         const char * fileName = keyString (parentKey);
     140             : 
     141           6 :         FILE * fp = NULL;
     142           6 :         fp = fopen (fileName, "wb");
     143           6 :         if (!fp)
     144             :         {
     145           0 :                 ELEKTRA_SET_RESOURCE_ERRORF (parentKey, "Failed to open %s for writing. Reason: %s", fileName, strerror (errno));
     146           0 :                 return -1;
     147             :         }
     148           6 :         ssize_t svalueSize = keyGetValueSize (key);
     149           6 :         if (svalueSize <= 0)
     150             :         {
     151           0 :                 fclose (fp);
     152           0 :                 return 0;
     153             :         }
     154           6 :         size_t valueSize = (size_t) svalueSize;
     155           6 :         unsigned char * value = elektraMalloc (valueSize);
     156           6 :         if (!value)
     157             :         {
     158           0 :                 ELEKTRA_MALLOC_ERROR (parentKey, valueSize);
     159           0 :                 fclose (fp);
     160           0 :                 return -1;
     161             :         }
     162           6 :         if (!keyIsBinary (key))
     163             :         {
     164           6 :                 keyGetString (key, (char *) value, valueSize);
     165           6 :                 valueSize -= 1; // don't write the null terminator to the file
     166             :         }
     167             :         else
     168             :         {
     169           0 :                 keyGetBinary (key, value, valueSize);
     170             :         }
     171           6 :         size_t bytesWritten = 0;
     172          18 :         while (bytesWritten < valueSize)
     173             :         {
     174           6 :                 size_t bytes = fwrite (value, 1, valueSize, fp);
     175           6 :                 if (bytes == 0) break;
     176           6 :                 bytesWritten += bytes;
     177             :         }
     178           6 :         fclose (fp);
     179           6 :         elektraFree (value);
     180             : 
     181           6 :         if (bytesWritten < valueSize)
     182             :         {
     183             :                 return -1;
     184             :         }
     185             : 
     186           6 :         return 1; // success
     187             : }
     188             : 
     189          57 : Plugin * ELEKTRA_PLUGIN_EXPORT
     190             : {
     191             :         // clang-format off
     192          57 :         return elektraPluginExport ("file",
     193             :                 ELEKTRA_PLUGIN_GET,     &elektraFileGet,
     194             :                 ELEKTRA_PLUGIN_SET,     &elektraFileSet,
     195             :                 ELEKTRA_PLUGIN_END);
     196             : }
     197             : 

Generated by: LCOV version 1.13