LCOV - code coverage report
Current view: top level - src/plugins/dump - dump.cpp (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 132 141 93.6 %
Date: 2019-09-12 12:28:41 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : #include "dump.hpp"
      10             : 
      11             : using namespace ckdb;
      12             : 
      13             : #include <fstream>
      14             : #include <iostream>
      15             : #include <sstream>
      16             : #include <string>
      17             : #include <vector>
      18             : 
      19             : #include <unistd.h>
      20             : 
      21             : #include <kdberrors.h>
      22             : #include <kdblogger.h>
      23             : 
      24             : namespace dump
      25             : {
      26             : 
      27        2472 : int serialise (std::ostream & os, ckdb::Key *, ckdb::KeySet * ks)
      28             : {
      29             :         ckdb::Key * cur;
      30             : 
      31        4944 :         os << "kdbOpen 1" << std::endl;
      32             : 
      33        9888 :         os << "ksNew " << ckdb::ksGetSize (ks) << std::endl;
      34             : 
      35        2472 :         ckdb::KeySet * metacopies = ckdb::ksNew (0, KS_END);
      36             : 
      37        2472 :         ksRewind (ks);
      38      146359 :         while ((cur = ksNext (ks)) != nullptr)
      39             :         {
      40      143887 :                 size_t namesize = ckdb::keyGetNameSize (cur);
      41      143887 :                 size_t valuesize = ckdb::keyGetValueSize (cur);
      42      719435 :                 os << "keyNew " << namesize << " " << valuesize << std::endl;
      43      143887 :                 os.write (ckdb::keyName (cur), namesize);
      44      143887 :                 os.write (static_cast<const char *> (ckdb::keyValue (cur)), valuesize);
      45      143887 :                 os << std::endl;
      46             : 
      47             :                 const ckdb::Key * meta;
      48      143887 :                 ckdb::keyRewindMeta (cur);
      49      427213 :                 while ((meta = ckdb::keyNextMeta (cur)) != nullptr)
      50             :                 {
      51      283326 :                         std::stringstream ss;
      52      283326 :                         ss << "user/" << meta; // use the address of pointer as name
      53             : 
      54      424989 :                         ckdb::Key * search = ckdb::keyNew (ss.str ().c_str (), KEY_END);
      55      141663 :                         ckdb::Key * ret = ksLookup (metacopies, search, 0);
      56             : 
      57      141663 :                         if (!ret)
      58             :                         {
      59             :                                 /* This metakey was not serialised up to now */
      60      141619 :                                 size_t metanamesize = ckdb::keyGetNameSize (meta);
      61      141619 :                                 size_t metavaluesize = ckdb::keyGetValueSize (meta);
      62             : 
      63      708095 :                                 os << "keyMeta " << metanamesize << " " << metavaluesize << std::endl;
      64      141619 :                                 os.write (ckdb::keyName (meta), metanamesize);
      65      141619 :                                 os.write (static_cast<const char *> (ckdb::keyValue (meta)), metavaluesize);
      66      141619 :                                 os << std::endl;
      67             : 
      68      283238 :                                 std::stringstream ssv;
      69      566476 :                                 ssv << namesize << " " << metanamesize << std::endl;
      70      141619 :                                 ssv.write (ckdb::keyName (cur), namesize);
      71      141619 :                                 ssv.write (ckdb::keyName (meta), metanamesize);
      72      708095 :                                 ckdb::keySetRaw (search, ssv.str ().c_str (), ssv.str ().size ());
      73             : 
      74      141619 :                                 ksAppendKey (metacopies, search);
      75             :                         }
      76             :                         else
      77             :                         {
      78             :                                 /* Meta key already serialised, write out a reference to it */
      79          44 :                                 keyDel (search);
      80             : 
      81          44 :                                 os << "keyCopyMeta ";
      82          44 :                                 os.write (static_cast<const char *> (ckdb::keyValue (ret)), ckdb::keyGetValueSize (ret));
      83             :                                 os << std::endl;
      84             :                         }
      85             :                 }
      86      143887 :                 os << "keyEnd" << std::endl;
      87             :         }
      88        4944 :         os << "ksEnd" << std::endl;
      89             : 
      90        2472 :         ksDel (metacopies);
      91             : 
      92        2472 :         return 1;
      93             : }
      94             : 
      95         957 : int unserialise (std::istream & is, ckdb::Key * errorKey, ckdb::KeySet * ks)
      96             : {
      97         957 :         ckdb::Key * cur = nullptr;
      98             : 
      99        3828 :         std::vector<char> namebuffer (4048);
     100        3828 :         std::vector<char> valuebuffer (4048);
     101        1914 :         std::string line;
     102         957 :         std::string command;
     103             :         size_t nrKeys;
     104             :         size_t namesize;
     105             :         size_t valuesize;
     106             : 
     107       39344 :         while (std::getline (is, line))
     108             :         {
     109       38381 :                 std::stringstream ss (line);
     110       19666 :                 ss >> command;
     111             : 
     112       19666 :                 if (command == "kdbOpen")
     113             :                 {
     114        1902 :                         std::string version;
     115         951 :                         ss >> version;
     116         951 :                         if (version != "1")
     117             :                         {
     118           0 :                                 ELEKTRA_SET_INSTALLATION_ERRORF (errorKey, "Wrong version detected in dumpfile: %s", version.c_str ());
     119           0 :                                 return -1;
     120             :                         }
     121             :                 }
     122       18715 :                 else if (command == "ksNew")
     123             :                 {
     124         951 :                         ss >> nrKeys;
     125             : 
     126         951 :                         ksClear (ks);
     127             :                 }
     128       17764 :                 else if (command == "keyNew")
     129             :                 {
     130        6406 :                         cur = ckdb::keyNew (nullptr);
     131             : 
     132        6406 :                         ss >> namesize;
     133        6406 :                         ss >> valuesize;
     134             : 
     135       12812 :                         if (namesize > namebuffer.size ()) namebuffer.resize (namesize + 1);
     136        6406 :                         is.read (&namebuffer[0], namesize);
     137       12812 :                         namebuffer[namesize] = 0;
     138        6406 :                         ckdb::keySetName (cur, &namebuffer[0]);
     139             : 
     140       12812 :                         if (valuesize > valuebuffer.size ()) valuebuffer.resize (valuesize + 1);
     141        6406 :                         is.read (&valuebuffer[0], valuesize);
     142       12812 :                         valuebuffer[valuesize] = 0;
     143             : 
     144        6406 :                         ckdb::keySetRaw (cur, &valuebuffer[0], valuesize);
     145        6406 :                         std::getline (is, line);
     146             :                 }
     147       11358 :                 else if (command == "keyMeta")
     148             :                 {
     149        3957 :                         ss >> namesize;
     150        3957 :                         ss >> valuesize;
     151             : 
     152        7914 :                         if (namesize > namebuffer.size ()) namebuffer.resize (namesize + 1);
     153        3957 :                         is.read (&namebuffer[0], namesize);
     154        7914 :                         namebuffer[namesize] = 0;
     155             : 
     156        7914 :                         if (valuesize > valuebuffer.size ()) valuebuffer.resize (valuesize + 1);
     157        3957 :                         is.read (&valuebuffer[0], valuesize);
     158        7914 :                         valuebuffer[valuesize] = 0;
     159             : 
     160        3957 :                         keySetMeta (cur, &namebuffer[0], &valuebuffer[0]);
     161        3957 :                         std::getline (is, line);
     162             :                 }
     163        7401 :                 else if (command == "keyCopyMeta")
     164             :                 {
     165          44 :                         ss >> namesize;
     166          44 :                         ss >> valuesize;
     167             : 
     168          88 :                         if (namesize > namebuffer.size ()) namebuffer.resize (namesize + 1);
     169          44 :                         is.read (&namebuffer[0], namesize);
     170          88 :                         namebuffer[namesize] = 0;
     171             : 
     172          88 :                         if (valuesize > valuebuffer.size ()) valuebuffer.resize (valuesize + 1);
     173          44 :                         is.read (&valuebuffer[0], valuesize);
     174          88 :                         valuebuffer[valuesize] = 0;
     175             : 
     176          44 :                         ckdb::Key * search = ckdb::ksLookupByName (ks, &namebuffer[0], 0);
     177          44 :                         ckdb::keyCopyMeta (cur, search, &valuebuffer[0]);
     178          44 :                         std::getline (is, line);
     179             :                 }
     180        7357 :                 else if (command == "keyEnd")
     181             :                 {
     182        6406 :                         ckdb::ksAppendKey (ks, cur);
     183             :                         cur = nullptr;
     184             :                 }
     185         951 :                 else if (command == "ksEnd")
     186             :                 {
     187             :                         break;
     188             :                 }
     189             :                 else
     190             :                 {
     191             :                         // TODO: Solution
     192           0 :                         ELEKTRA_SET_VALIDATION_SYNTACTIC_ERRORF (
     193             :                                 errorKey,
     194             :                                 "Unknown command detected in dumpfile: %s.\nMaybe you use a different file format? "
     195             :                                 "Try to remount with another plugin (eg. ini, ni, etc.)",
     196             :                                 command.c_str ());
     197             :                         return -1;
     198             :                 }
     199             :         }
     200             :         return 1;
     201             : }
     202             : 
     203             : class pipebuf : public std::streambuf
     204             : {
     205             :         char * buffer_;
     206             :         int fd_;
     207             : 
     208             : public:
     209        1152 :         pipebuf (int fd) : buffer_ (new char[4096]), fd_ (fd)
     210             :         {
     211         576 :         }
     212         576 :         ~pipebuf ()
     213        1728 :         {
     214         576 :                 delete[] this->buffer_;
     215         576 :         }
     216        3659 :         int underflow ()
     217             :         {
     218        3659 :                 if (this->gptr () == this->egptr ())
     219             :                 {
     220             :                         // read from the pipe directly into the buffer
     221        3659 :                         ssize_t r = read (fd_, buffer_, 4096);
     222        3659 :                         this->setg (this->buffer_, this->buffer_, this->buffer_ + r);
     223             :                 }
     224        7314 :                 return this->gptr () == this->egptr () ? std::char_traits<char>::eof () :
     225        7314 :                                                          std::char_traits<char>::to_int_type (*this->gptr ());
     226             :         }
     227             : };
     228             : 
     229             : } // namespace dump
     230             : 
     231             : extern "C" {
     232             : 
     233        3226 : int elektraDumpGet (ckdb::Plugin *, ckdb::KeySet * returned, ckdb::Key * parentKey)
     234             : {
     235        3226 :         Key * root = ckdb::keyNew ("system/elektra/modules/dump", KEY_END);
     236        3226 :         if (keyRel (root, parentKey) >= 0)
     237             :         {
     238        2269 :                 keyDel (root);
     239        2269 :                 KeySet * n = ksNew (50, keyNew ("system/elektra/modules/dump", KEY_VALUE, "dump plugin waits for your orders", KEY_END),
     240             :                                     keyNew ("system/elektra/modules/dump/exports", KEY_END),
     241             :                                     keyNew ("system/elektra/modules/dump/exports/get", KEY_FUNC, elektraDumpGet, KEY_END),
     242             :                                     keyNew ("system/elektra/modules/dump/exports/set", KEY_FUNC, elektraDumpSet, KEY_END),
     243             :                                     keyNew ("system/elektra/modules/dump/exports/serialise", KEY_FUNC, dump::serialise, KEY_END),
     244             :                                     keyNew ("system/elektra/modules/dump/exports/unserialise", KEY_FUNC, dump::unserialise, KEY_END),
     245             :                                     keyNew ("system/elektra/modules/dump/config/needs/fcrypt/textmode", KEY_VALUE, "0", KEY_END),
     246             : #include "readme_dump.c"
     247        2269 :                                     keyNew ("system/elektra/modules/dump/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END);
     248        2269 :                 ksAppend (returned, n);
     249        2269 :                 ksDel (n);
     250             :                 return 1;
     251             :         }
     252         957 :         keyDel (root);
     253         957 :         int errnosave = errno;
     254             : 
     255             :         // We use dump for the pluginprocess library. Unfortunately on macOS reading from /dev/fd/<fd> via
     256             :         // ifstream fails, thus we read directly from unnamed pipes using a custom buffer and read
     257         957 :         const char pipe[] = "/dev/fd/";
     258         957 :         if (!strncmp (keyString (parentKey), pipe, strlen (pipe)))
     259             :         {
     260        2304 :                 int fd = std::stoi (std::string (keyString (parentKey) + strlen (pipe)));
     261        1152 :                 dump::pipebuf pipebuf (fd);
     262        1152 :                 std::istream is (&pipebuf);
     263         576 :                 return dump::unserialise (is, parentKey, returned);
     264             :         }
     265             :         else
     266             :         {
     267             :                 // ELEKTRA_LOG (ELEKTRA_LOG_MODULE_DUMP, "opening file %s", keyString (parentKey));
     268         762 :                 std::ifstream is (keyString (parentKey), std::ios::binary);
     269             : 
     270         381 :                 if (!is.is_open ())
     271             :                 {
     272           0 :                         ELEKTRA_SET_ERROR_GET (parentKey);
     273           0 :                         errno = errnosave;
     274           0 :                         return -1;
     275             :                 }
     276             : 
     277         381 :                 return dump::unserialise (is, parentKey, returned);
     278             :         }
     279             : }
     280             : 
     281        2472 : int elektraDumpSet (ckdb::Plugin *, ckdb::KeySet * returned, ckdb::Key * parentKey)
     282             : {
     283        2472 :         int errnosave = errno;
     284             :         // ELEKTRA_LOG (ELEKTRA_LOG_MODULE_DUMP, "opening file %s", keyString (parentKey));
     285        4944 :         std::ofstream ofs (keyString (parentKey), std::ios::binary);
     286        2472 :         if (!ofs.is_open ())
     287             :         {
     288           0 :                 ELEKTRA_SET_ERROR_SET (parentKey);
     289           0 :                 errno = errnosave;
     290           0 :                 return -1;
     291             :         }
     292             : 
     293        2472 :         return dump::serialise (ofs, parentKey, returned);
     294             : }
     295             : 
     296        7484 : ckdb::Plugin * ELEKTRA_PLUGIN_EXPORT
     297             : {
     298             :         // clang-format off
     299             :         return elektraPluginExport("dump",
     300             :                 ELEKTRA_PLUGIN_GET,             &elektraDumpGet,
     301             :                 ELEKTRA_PLUGIN_SET,             &elektraDumpSet,
     302        7484 :                 ELEKTRA_PLUGIN_END);
     303             : }
     304             : 
     305        2792 : } // extern C
     306             : 

Generated by: LCOV version 1.13