LCOV - code coverage report
Current view: top level - src/plugins/resolver - filename.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 249 315 79.0 %
Date: 2019-09-12 12:28:41 Functions: 45 51 88.2 %

          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 "resolver.h"
      10             : 
      11             : #include <errno.h>
      12             : #include <kdbhelper.h>
      13             : #include <kdbtypes.h>
      14             : #include <libgen.h>
      15             : #include <pwd.h>
      16             : #include <stdbool.h>
      17             : #include <stdio.h>
      18             : #include <stdlib.h>
      19             : #include <string.h>
      20             : #include <sys/time.h>
      21             : #include <sys/types.h>
      22             : #include <unistd.h>
      23             : 
      24             : 
      25             : #define POSTFIX_SIZE 50
      26             : 
      27             : 
      28             : /**
      29             :  * Check if supplied filename is ok.
      30             :  *
      31             :  * This symbol is exported and used during mounting.
      32             :  *
      33             :  * @retval 1 on success (Relative path)
      34             :  * @retval 0 on success (Absolute path)
      35             :  * @retval -1 on a non-valid file
      36             :  */
      37         726 : int ELEKTRA_PLUGIN_FUNCTION (checkFile) (const char * filename)
      38             : {
      39         726 :         if (!filename) return -1;
      40         726 :         if (filename[0] == '0') return -1;
      41             : 
      42         726 :         size_t size = strlen (filename);
      43         726 :         char * buffer = elektraMalloc (size + sizeof ("system/"));
      44         726 :         strcpy (buffer, "system/");
      45         726 :         strcat (buffer, filename);
      46             : 
      47             :         /* Because of the outbreak bugs these tests are not enough */
      48         726 :         Key * check = keyNew (buffer, KEY_END);
      49         726 :         if (!strcmp (keyName (check), "")) goto error;
      50         726 :         if (!strcmp (keyName (check), "system")) goto error;
      51         716 :         keyDel (check);
      52         716 :         elektraFree (buffer);
      53             : 
      54             :         /* Be strict, don't allow any .., even if it would be ok sometimes */
      55         716 :         if (strstr (filename, "..") != 0) return -1;
      56             : 
      57         704 :         if (filename[0] == '/') return 0;
      58             : 
      59         582 :         return 1;
      60             : 
      61             : error:
      62          10 :         keyDel (check);
      63          10 :         elektraFree (buffer);
      64          10 :         return -1;
      65             : }
      66             : 
      67      159117 : static void elektraGenTempFilename (ElektraResolved * handle, ElektraResolveTempfile tmpDir)
      68             : {
      69      159117 :         char * tmpFile = NULL;
      70      159117 :         size_t len = 0;
      71      159117 :         size_t tmpFilenameSize = 0;
      72      159117 :         if (tmpDir == ELEKTRA_RESOLVER_TEMPFILE_SAMEDIR)
      73             :         {
      74      159117 :                 tmpFilenameSize = strlen (handle->fullPath) + POSTFIX_SIZE;
      75      159117 :                 tmpFile = elektraCalloc (tmpFilenameSize);
      76      159117 :                 len = sprintf (tmpFile, "%s", handle->fullPath);
      77             :         }
      78           0 :         else if (tmpDir == ELEKTRA_RESOLVER_TEMPFILE_TMPDIR)
      79             :         {
      80           0 :                 tmpFilenameSize = sizeof ("/tmp/") + strlen (handle->fullPath) + POSTFIX_SIZE;
      81           0 :                 tmpFile = elektraCalloc (tmpFilenameSize);
      82           0 :                 len = sprintf (tmpFile, "/tmp/%s", handle->fullPath);
      83             :         }
      84             : 
      85             :         struct timeval tv;
      86      159117 :         memset (&tv, 0, sizeof (struct timeval));
      87      159117 :         gettimeofday (&tv, 0);
      88      159117 :         snprintf (tmpFile + len, POSTFIX_SIZE - 1, ".%d:%ld." ELEKTRA_TIME_USEC_F ".tmp", getpid (), tv.tv_sec, tv.tv_usec);
      89      159117 :         handle->tmpFile = tmpFile;
      90      159117 : }
      91             : 
      92      159133 : static void elektraResolveFinishByFilename (ElektraResolved * handle, ElektraResolveTempfile tmpDir)
      93             : {
      94      159133 :         size_t filenameSize = strlen (handle->fullPath);
      95      159133 :         char * dir = elektraMalloc (filenameSize);
      96      159133 :         char * dup = elektraStrDup (handle->fullPath);
      97      159133 :         strcpy (dir, dirname (dup));
      98      159133 :         elektraFree (dup);
      99      159133 :         handle->dirname = dir;
     100             : 
     101      159133 :         switch (tmpDir)
     102             :         {
     103             :         case ELEKTRA_RESOLVER_TEMPFILE_NONE:
     104             :                 return;
     105             :         case ELEKTRA_RESOLVER_TEMPFILE_SAMEDIR:
     106      159117 :                 elektraGenTempFilename (handle, tmpDir);
     107      159117 :                 return;
     108             :         case ELEKTRA_RESOLVER_TEMPFILE_TMPDIR:
     109           0 :                 elektraGenTempFilename (handle, tmpDir);
     110           0 :                 return;
     111             :         }
     112             : }
     113             : 
     114       39809 : static void elektraResolveUsingHome (ElektraResolved * handle, const char * home, short addPostfix)
     115             : {
     116       39809 :         Key * canonify = keyNew ("user", KEY_END);
     117       39809 :         keyAddName (canonify, home);
     118             : 
     119       39809 :         size_t dirnameSize = keyGetNameSize (canonify) + sizeof ("/" KDB_DB_USER);
     120       39809 :         char * dir = elektraMalloc (dirnameSize);
     121             : 
     122       39809 :         strcpy (dir, keyName (canonify) + 4); // cut user, leave slash
     123       39809 :         if (addPostfix && handle->relPath[0] != '/')
     124             :         {
     125       39498 :                 strcat (dir, "/" KDB_DB_USER);
     126             :         }
     127       39809 :         handle->dirname = dir;
     128       39809 :         keyDel (canonify);
     129       39809 : }
     130             : 
     131        1028 : static char * elektraResolvePasswd (Key * warningsKey)
     132             : {
     133        1028 :         ssize_t bufSize = sysconf (_SC_GETPW_R_SIZE_MAX);
     134        1028 :         if (bufSize == -1) bufSize = 16384; // man 3 getpwuid
     135             : 
     136        1028 :         char * buf = elektraMalloc (bufSize);
     137        1028 :         if (!buf) return NULL;
     138             :         struct passwd pwd;
     139             :         struct passwd * result;
     140             : 
     141        1028 :         int s = getpwuid_r (getuid (), &pwd, buf, bufSize, &result);
     142        1028 :         if (result == NULL)
     143             :         {
     144           0 :                 elektraFree (buf);
     145           0 :                 if (s != 0)
     146             :                 {
     147           0 :                         ELEKTRA_ADD_INSTALLATION_WARNINGF (warningsKey, "Could not retrieve from passwd using getpwuid_r. Reason: %s",
     148             :                                                            strerror (s));
     149             :                 }
     150             :                 return NULL;
     151             :         }
     152        1028 :         char * resolved = elektraStrDup (pwd.pw_dir);
     153        1028 :         elektraFree (buf);
     154        1028 :         return resolved;
     155             : }
     156             : 
     157        1028 : static int elektraResolveUserPasswd (ElektraResolved * handle, Key * warningsKey)
     158             : {
     159        1028 :         char * dir = elektraResolvePasswd (warningsKey);
     160        1028 :         if (!dir) return 0;
     161        1028 :         elektraResolveUsingHome (handle, dir, 1);
     162        1028 :         elektraFree (dir);
     163        1028 :         return 1;
     164             : }
     165             : 
     166           0 : static int elektraResolveSystemPasswd (ElektraResolved * handle, Key * warningsKey)
     167             : {
     168           0 :         char * dir = elektraResolvePasswd (warningsKey);
     169           0 :         if (!dir) return -1;
     170           0 :         size_t filenameSize = elektraStrLen (dir) + elektraStrLen (handle->relPath) - 1;
     171           0 :         char * resolved = elektraMalloc (filenameSize);
     172           0 :         snprintf (resolved, filenameSize, "%s/%s", dir, handle->relPath + 2);
     173           0 :         elektraFree (dir);
     174           0 :         handle->fullPath = resolved;
     175             :         return 0;
     176             : }
     177             : 
     178          23 : static int elektraResolveUserXDGHome (ElektraResolved * handle, Key * warningsKey)
     179             : {
     180          23 :         const char * home = getenv ("XDG_CONFIG_HOME");
     181             : 
     182          23 :         if (!home || !strcmp (home, ""))
     183             :         {
     184             :                 return 0;
     185             :         }
     186             : 
     187          23 :         if (home[0] != '/')
     188             :         {
     189           0 :                 ELEKTRA_ADD_VALIDATION_SYNTACTIC_WARNINGF (warningsKey,
     190             :                                                            "XDG_CONFIG_HOME contains a path that is "
     191             :                                                            "not absolute (violates XDG specification) and thus "
     192             :                                                            "it was skipped: %s",
     193             :                                                            home);
     194           0 :                 return 0;
     195             :         }
     196          23 :         elektraResolveUsingHome (handle, home, 0);
     197          23 :         return 1;
     198             : }
     199             : 
     200       39784 : static int elektraResolveEnvHome (ElektraResolved * handle, Key * warningsKey)
     201             : {
     202       39784 :         const char * home = getenv ("HOME");
     203             : 
     204       39784 :         if (!home || !strcmp (home, ""))
     205             :         {
     206             :                 return 0;
     207             :         }
     208             : 
     209       38758 :         if (home[0] != '/')
     210             :         {
     211           0 :                 ELEKTRA_ADD_VALIDATION_SYNTACTIC_WARNINGF (warningsKey,
     212             :                                                            "HOME contains a path that is "
     213             :                                                            "not absolute and thus "
     214             :                                                            "it was skipped: %s",
     215             :                                                            home);
     216           0 :                 return 0;
     217             :         }
     218       38758 :         elektraResolveUsingHome (handle, home, 1);
     219       38758 :         return 1;
     220             : }
     221             : 
     222         190 : static int elektraResolveEnvUser (ElektraResolved * handle)
     223             : {
     224         190 :         const char * user = getenv ("USER");
     225             : 
     226         190 :         if (!user || !strcmp (user, ""))
     227             :         {
     228             :                 return 0;
     229             :         }
     230             : 
     231          17 :         Key * canonify = keyNew ("user", KEY_END);
     232          17 :         keyAddName (canonify, user);
     233          17 :         size_t homeSize = sizeof (KDB_DB_HOME "/") + keyGetNameSize (canonify) + sizeof ("/" KDB_DB_USER);
     234             : 
     235          17 :         char * homeBuf = elektraMalloc (homeSize);
     236          17 :         strcpy (homeBuf, KDB_DB_HOME "/");
     237          17 :         strcat (homeBuf, keyName (canonify) + 5); // cut user/
     238          17 :         if (handle->relPath[0] != '/')
     239             :         {
     240          17 :                 strcat (homeBuf, "/" KDB_DB_USER);
     241             :         }
     242          17 :         keyDel (canonify);
     243          17 :         handle->dirname = homeBuf;
     244             :         return 1;
     245             : }
     246             : 
     247         641 : static int elektraResolveUserBuildin (ElektraResolved * handle)
     248             : {
     249         641 :         size_t homeSize = sizeof (KDB_DB_HOME "/") + sizeof ("/" KDB_DB_USER);
     250             : 
     251         641 :         char * homeBuf = elektraMalloc (homeSize);
     252         641 :         snprintf (homeBuf, homeSize, "%s", KDB_DB_HOME);
     253         641 :         if (handle->relPath[0] != '/')
     254             :         {
     255         633 :                 strcat (homeBuf, "/" KDB_DB_USER);
     256             :         }
     257         641 :         handle->dirname = homeBuf;
     258         641 :         return 1;
     259             : }
     260             : 
     261       41666 : static int elektraResolveUser (char variant, ElektraResolved * handle, Key * warningsKey)
     262             : {
     263       41666 :         switch (variant)
     264             :         {
     265             :         case 'p':
     266        1028 :                 return elektraResolveUserPasswd (handle, warningsKey);
     267             :         case 'x':
     268          23 :                 return elektraResolveUserXDGHome (handle, warningsKey);
     269             :         case 'h':
     270       39784 :                 return elektraResolveEnvHome (handle, warningsKey);
     271             :         case 'u':
     272         190 :                 return elektraResolveEnvUser (handle);
     273             :         case 'b':
     274         641 :                 return elektraResolveUserBuildin (handle);
     275             :         }
     276             :         return -1;
     277             : }
     278             : 
     279       40467 : static void elektraResolveFinishByDirname (ElektraResolved * handle, ElektraResolveTempfile tmpDir)
     280             : {
     281       40467 :         size_t filenameSize = elektraStrLen (handle->relPath) + elektraStrLen (handle->dirname);
     282       40467 :         char * filename = elektraMalloc (filenameSize);
     283       40467 :         strcpy (filename, handle->dirname);
     284       40467 :         if (handle->relPath[0] != '/')
     285             :         {
     286       40171 :                 strcat (filename, "/");
     287             :         }
     288       40467 :         strcat (filename, handle->relPath);
     289       40467 :         elektraFree (handle->dirname);
     290       40467 :         handle->fullPath = filename;
     291       40467 :         elektraResolveFinishByFilename (handle, tmpDir);
     292       40467 : }
     293             : 
     294       40467 : static int elektraResolveMapperUser (ElektraResolved * handle, ElektraResolveTempfile tmpDir, Key * warningsKey)
     295             : {
     296       40467 :         int finished = 0;
     297             :         size_t i;
     298       82133 :         for (i = 0; !finished && i < sizeof (ELEKTRA_VARIANT_USER); ++i)
     299             :         {
     300       41666 :                 finished = elektraResolveUser (ELEKTRA_VARIANT_USER[i], handle, warningsKey);
     301             :         }
     302       40467 :         if (finished == -1)
     303             :         {
     304           0 :                 ELEKTRA_ADD_PLUGIN_MISBEHAVIOR_WARNINGF (warningsKey, "User resolver failed at step %zu, the configuration is: %s", i,
     305             :                                                          ELEKTRA_VARIANT_USER);
     306           0 :                 return -1;
     307             :         }
     308             : 
     309       40467 :         if (!(handle->dirname))
     310             :         {
     311           0 :                 ELEKTRA_ADD_INSTALLATION_WARNINGF (warningsKey, "No resolver set the user dirname, the configuration is: %s",
     312             :                                                    ELEKTRA_VARIANT_USER);
     313           0 :                 return -1;
     314             :         }
     315             : 
     316       40467 :         elektraResolveFinishByDirname (handle, tmpDir);
     317             : 
     318       40467 :         return finished;
     319             : }
     320             : 
     321       38519 : static int elektraResolveSystemBuildin (ElektraResolved * handle, ElektraResolveTempfile tmpDir, Key * warningsKey)
     322             : {
     323       38519 :         size_t filenameSize = sizeof (KDB_DB_SYSTEM) + elektraStrLen (handle->relPath) + sizeof ("/");
     324       38519 :         char * resolved = NULL;
     325             :         if (KDB_DB_SYSTEM[0] == '~')
     326             :         {
     327             :                 char * resolvedPath = elektraMalloc (filenameSize);
     328             :                 strcpy (resolvedPath, KDB_DB_SYSTEM);
     329             :                 strcat (resolvedPath, "/");
     330             :                 strcat (resolvedPath, handle->relPath);
     331             :                 char * oldPath = handle->relPath;
     332             :                 handle->relPath = resolvedPath;
     333             :                 elektraResolveSystemPasswd (handle, warningsKey);
     334             :                 elektraFree (resolvedPath);
     335             :                 handle->relPath = oldPath;
     336             :         }
     337             :         else
     338             :         {
     339       38519 :                 resolved = elektraMalloc (filenameSize);
     340       38519 :                 strcpy (resolved, KDB_DB_SYSTEM);
     341       38519 :                 strcat (resolved, "/");
     342       38519 :                 strcat (resolved, handle->relPath);
     343       38519 :                 handle->fullPath = resolved;
     344             :         }
     345       38519 :         elektraResolveFinishByFilename (handle, tmpDir);
     346       38519 :         return 1;
     347             : }
     348             : 
     349         275 : static void elektraResolveSystemXDGHelper (char ** filename, const char * path, const char * result)
     350             : {
     351         275 :         size_t configDirSize = elektraStrLen (result);
     352         275 :         size_t pathSize = elektraStrLen (path);
     353         275 :         size_t filenameSize = configDirSize + pathSize + sizeof ("/") + 1;
     354             : 
     355         275 :         elektraRealloc ((void **) filename, filenameSize);
     356         275 :         strcpy (*filename, result);
     357         275 :         strcat (*filename, "/");
     358         275 :         strcat (*filename, path);
     359         275 : }
     360             : 
     361         241 : static int elektraResolveSystemXDG (ElektraResolved * handle, ElektraResolveTempfile tmpDir, Key * warningsKey)
     362             : {
     363         241 :         const char * configDir = getenv ("XDG_CONFIG_DIRS");
     364         241 :         const char * defaultDir = "/etc/xdg";
     365         241 :         char * filename = NULL;
     366         241 :         if (!configDir || !strcmp (configDir, ""))
     367             :         {
     368         197 :                 elektraResolveSystemXDGHelper (&filename, handle->relPath, defaultDir);
     369         197 :                 handle->fullPath = filename;
     370         197 :                 elektraResolveFinishByFilename (handle, tmpDir);
     371         197 :                 return 1;
     372             :         }
     373             : 
     374          44 :         char * saveptr = 0;
     375          44 :         char * str = elektraStrDup (configDir);
     376          88 :         char * result = strtok_r (str, ":", &saveptr);
     377             :         struct stat buf;
     378          44 :         int errnoSave = errno;
     379          44 :         int success = 0;
     380         166 :         while (result)
     381             :         {
     382          78 :                 if (result[0] != '/')
     383             :                 {
     384           0 :                         ELEKTRA_ADD_VALIDATION_SYNTACTIC_WARNINGF (warningsKey,
     385             :                                                                    "XDG_CONFIG_DIRS contains a path that is "
     386             :                                                                    "not absolute (violates XDG specification) and thus "
     387             :                                                                    "it was skipped: %s",
     388             :                                                                    result);
     389             : 
     390           0 :                         result = strtok_r (0, ":", &saveptr);
     391           0 :                         continue;
     392             :                 }
     393             : 
     394          78 :                 success = 1; // at least once we got a valid path
     395             : 
     396          78 :                 elektraResolveSystemXDGHelper (&filename, handle->relPath, result);
     397             : 
     398         156 :                 if (stat (filename, &buf) == 0)
     399             :                 {
     400             :                         // we found a file!
     401             :                         break;
     402             :                 }
     403             : 
     404             :                 result = strtok_r (0, ":", &saveptr);
     405             :         }
     406          44 :         elektraFree (str);
     407          44 :         errno = errnoSave;
     408             : 
     409          44 :         if (!success)
     410             :         {
     411           0 :                 elektraResolveSystemXDGHelper (&filename, handle->relPath, defaultDir);
     412             :         }
     413          44 :         handle->fullPath = filename;
     414          44 :         elektraResolveFinishByFilename (handle, tmpDir);
     415          44 :         return 1;
     416             : }
     417             : 
     418             : /**
     419             :  * @retval 0 if variant did not have a result
     420             :  * @retval 1 on success
     421             :  */
     422       39703 : static int elektraResolveSystem (char variant, ElektraResolved * handle, ElektraResolveTempfile tmpDir, Key * warningsKey)
     423             : {
     424             :         // hardcoded path wins against variants for now
     425       39703 :         if (handle->relPath[0] == '/')
     426             :         {
     427             :                 /* Use absolute path */
     428         943 :                 handle->fullPath = elektraStrDup (handle->relPath);
     429         943 :                 elektraResolveFinishByFilename (handle, tmpDir);
     430         943 :                 return 1;
     431             :         }
     432       38760 :         if (handle->relPath[0] == '~')
     433             :         {
     434           0 :                 if (elektraResolveSystemPasswd (handle, warningsKey) == -1)
     435             :                 {
     436             :                         return -1;
     437             :                 }
     438           0 :                 elektraResolveFinishByFilename (handle, tmpDir);
     439           0 :                 return 1;
     440             :         }
     441       38760 :         switch (variant)
     442             :         {
     443             :         case 'x':
     444         241 :                 return elektraResolveSystemXDG (handle, tmpDir, warningsKey);
     445             :         case 'b':
     446       38519 :                 return elektraResolveSystemBuildin (handle, tmpDir, warningsKey);
     447             :                 // TODO: also document in doc/COMPILE.md
     448             :         }
     449             :         return -1;
     450             : }
     451       39703 : static int elektraResolveMapperSystem (ElektraResolved * handle, ElektraResolveTempfile tmpDir, Key * warningsKey)
     452             : {
     453       39703 :         int finished = 0;
     454             :         size_t i;
     455       79406 :         for (i = 0; !finished && i < sizeof (ELEKTRA_VARIANT_SYSTEM); ++i)
     456             :         {
     457       39703 :                 finished = elektraResolveSystem (ELEKTRA_VARIANT_SYSTEM[i], handle, tmpDir, warningsKey);
     458             :         }
     459       39703 :         if (finished == -1)
     460             :         {
     461           0 :                 ELEKTRA_ADD_INSTALLATION_WARNINGF (warningsKey, "No resolver set the user dirname, the configuration is: %s",
     462             :                                                    ELEKTRA_VARIANT_USER);
     463           0 :                 return -1;
     464             :         }
     465             : 
     466       39703 :         if (!(handle->fullPath))
     467             :         {
     468           0 :                 ELEKTRA_ADD_INSTALLATION_WARNINGF (warningsKey, "No resolver set the system dirname, the configuration is: %s",
     469             :                                                    ELEKTRA_VARIANT_SYSTEM);
     470           0 :                 return -1;
     471             :         }
     472             : 
     473             :         return finished;
     474             : }
     475             : 
     476             : /**
     477             :  * @return freshly allocated buffer with current working directory
     478             :  *
     479             :  * @param warningsKey where warnings are added
     480             :  */
     481       38870 : static char * elektraGetCwd (Key * warningsKey)
     482             : {
     483       38870 :         int size = 4096;
     484       38870 :         char * cwd = elektraMalloc (size);
     485       38870 :         if (cwd == NULL)
     486             :         {
     487           0 :                 ELEKTRA_ADD_OUT_OF_MEMORY_WARNING (warningsKey, "Could not alloc for getcwd, defaulting to /");
     488           0 :                 return 0;
     489             :         }
     490             : 
     491             :         char * ret = NULL;
     492       77740 :         while (ret == NULL)
     493             :         {
     494       38870 :                 ret = getcwd (cwd, size);
     495             : 
     496       38870 :                 if (ret == NULL)
     497             :                 {
     498           0 :                         if (errno != ERANGE)
     499             :                         {
     500             :                                 // give up, we cannot handle the problem
     501           0 :                                 elektraFree (cwd);
     502           0 :                                 ELEKTRA_ADD_RESOURCE_WARNINGF (warningsKey, "Method 'getcwd()' failed. Defaulting to /. Reason: %s",
     503             :                                                                strerror (errno));
     504           0 :                                 return 0;
     505             :                         }
     506             : 
     507             :                         // try to double the space
     508           0 :                         size *= 2;
     509           0 :                         elektraRealloc ((void **) &cwd, size);
     510           0 :                         if (cwd == NULL)
     511             :                         {
     512           0 :                                 ELEKTRA_ADD_OUT_OF_MEMORY_WARNINGF (warningsKey,
     513             :                                                                     "Could not realloc for `getcwd()` size %d, defaulting to /", size);
     514           0 :                                 return 0;
     515             :                         }
     516             :                 }
     517             :         }
     518             : 
     519             :         return ret;
     520             : }
     521             : 
     522             : 
     523       40093 : static int elektraResolveSpec (ElektraResolved * handle, ElektraResolveTempfile tmpDir, Key * warningsKey ELEKTRA_UNUSED)
     524             : {
     525       40093 :         size_t filenameSize = sizeof (KDB_DB_SPEC) + strlen (handle->relPath) + sizeof ("/") + 1;
     526       40093 :         if (handle->relPath[0] == '/')
     527             :         {
     528         304 :                 char * filename = NULL;
     529         304 :                 filename = elektraMalloc (filenameSize);
     530         304 :                 strcpy (filename, handle->relPath);
     531         304 :                 handle->fullPath = filename;
     532             :         }
     533       39789 :         else if (handle->relPath[0] == '~')
     534             :         {
     535           0 :                 if (elektraResolveSystemPasswd (handle, warningsKey) == -1)
     536             :                 {
     537             :                         return -1;
     538             :                 }
     539             :         }
     540             :         else if (KDB_DB_SPEC[0] == '~')
     541             :         {
     542             :                 char * oldPath = handle->relPath;
     543             :                 char * path = elektraMalloc (filenameSize);
     544             :                 strcpy (path, KDB_DB_SPEC);
     545             :                 strcat (path, "/");
     546             :                 strcat (path, handle->relPath);
     547             :                 handle->relPath = path;
     548             :                 elektraResolveSystemPasswd (handle, warningsKey);
     549             :                 elektraFree (path);
     550             :                 handle->relPath = oldPath;
     551             :         }
     552             :         else
     553             :         {
     554       39789 :                 char * path = elektraMalloc (filenameSize);
     555       39789 :                 strcpy (path, KDB_DB_SPEC);
     556       39789 :                 strcat (path, "/");
     557       39789 :                 strcat (path, handle->relPath);
     558       39789 :                 handle->fullPath = path;
     559             :         }
     560             : 
     561       40093 :         elektraResolveFinishByFilename (handle, tmpDir);
     562       40093 :         return 1;
     563             : }
     564             : 
     565             : 
     566       38870 : static int elektraResolveDir (ElektraResolved * handle, ElektraResolveTempfile tmpDir, Key * warningsKey)
     567             : {
     568       38870 :         char * cwd = elektraGetCwd (warningsKey);
     569       38870 :         if (!cwd)
     570             :         {
     571           0 :                 cwd = elektraStrDup ("/");
     572             :         }
     573       38870 :         char * dn = elektraStrDup (cwd);
     574       38870 :         char * dnOrig = dn;
     575             : 
     576             :         char * filename;
     577             : 
     578             :         while (true)
     579      214334 :         {
     580             :                 // now put together the filename
     581      253204 :                 filename = handle->relPath[0] == '/' ? elektraFormat ("%s%s", dn, handle->relPath) :
     582             :                                                        elektraFormat ("%s/" KDB_DB_DIR "/%s", dn, handle->relPath);
     583             : 
     584             :                 struct stat buf;
     585      253204 :                 if (stat (filename, &buf) == 0)
     586             :                 {
     587             :                         // we found a file!
     588             :                         break;
     589             :                 }
     590             : 
     591      252914 :                 if (!strcmp (dn, "/"))
     592             :                 {
     593             :                         // we reached the end, filename not useful anymore
     594             :                         break;
     595             :                 }
     596             : 
     597      214334 :                 elektraFree (filename);
     598      214334 :                 dn = dirname (dn);
     599             :         }
     600             : 
     601       38870 :         if (!strcmp (dn, "/"))
     602             :         {
     603             :                 // nothing found, so we use most specific
     604       38820 :                 elektraFree (filename);
     605       38820 :                 filename = handle->relPath[0] == '/' ? elektraFormat ("%s%s", cwd, handle->relPath) :
     606             :                                                        elektraFormat ("%s/" KDB_DB_DIR "/%s", cwd, handle->relPath);
     607             :         }
     608             : 
     609       38870 :         elektraFree (cwd);
     610       38870 :         elektraFree (dnOrig);
     611       38870 :         handle->fullPath = filename;
     612       38870 :         elektraResolveFinishByFilename (handle, tmpDir);
     613       38870 :         return 1;
     614             : }
     615             : 
     616      159133 : void ELEKTRA_PLUGIN_FUNCTION (freeHandle) (ElektraResolved * handle)
     617             : {
     618      159133 :         if (!handle) return;
     619      159133 :         if (handle->relPath != NULL) elektraFree (handle->relPath);
     620      159133 :         if (handle->dirname != NULL) elektraFree (handle->dirname);
     621      159133 :         if (handle->fullPath != NULL) elektraFree (handle->fullPath);
     622      159133 :         if (handle->tmpFile != NULL) elektraFree (handle->tmpFile);
     623      159133 :         elektraFree (handle);
     624      159133 :         handle = NULL;
     625             : }
     626             : 
     627      159133 : ElektraResolved * ELEKTRA_PLUGIN_FUNCTION (filename) (elektraNamespace namespace, const char * path, ElektraResolveTempfile tmpDir,
     628             :                                                       Key * warningsKey)
     629             : {
     630             : 
     631      159133 :         ElektraResolved * handle = elektraCalloc (sizeof (ElektraResolved));
     632      159133 :         handle->relPath = elektraStrDup (path);
     633             : 
     634      159133 :         int rc = 0;
     635             : 
     636      159133 :         switch (namespace)
     637             :         {
     638             :         case KEY_NS_SPEC:
     639       40093 :                 rc = elektraResolveSpec (handle, tmpDir, warningsKey);
     640       40093 :                 break;
     641             :         case KEY_NS_DIR:
     642       38870 :                 rc = elektraResolveDir (handle, tmpDir, warningsKey);
     643       38870 :                 break;
     644             :         case KEY_NS_USER:
     645       40467 :                 rc = elektraResolveMapperUser (handle, tmpDir, warningsKey);
     646       40467 :                 break;
     647             :         case KEY_NS_SYSTEM:
     648       39703 :                 rc = elektraResolveMapperSystem (handle, tmpDir, warningsKey);
     649       39703 :                 break;
     650             :         case KEY_NS_PROC:
     651           0 :                 ELEKTRA_ADD_INTERFACE_WARNING (warningsKey, "Resolver was not able to resolve a filename. Tried to resolve proc");
     652           0 :                 rc = -1;
     653           0 :                 break;
     654             :         case KEY_NS_EMPTY:
     655           0 :                 ELEKTRA_ADD_INTERFACE_WARNING (warningsKey, "Resolver was not able to resolve a filename. Tried to resolve empty");
     656           0 :                 rc = -1;
     657           0 :                 break;
     658             :         case KEY_NS_NONE:
     659           0 :                 ELEKTRA_ADD_INTERFACE_WARNING (warningsKey, "Resolver was not able to resolve a filename. Tried to resolve none");
     660           0 :                 rc = -1;
     661           0 :                 break;
     662             :         case KEY_NS_META:
     663           0 :                 ELEKTRA_ADD_INTERFACE_WARNING (warningsKey, "Resolver was not able to resolve a filename. Tried to resolve meta");
     664           0 :                 rc = -1;
     665           0 :                 break;
     666             :         case KEY_NS_CASCADING:
     667           0 :                 ELEKTRA_ADD_INTERFACE_WARNING (warningsKey, "Resolver was not able to resolve a filename. Tried to resolve cascading");
     668           0 :                 rc = -1;
     669           0 :                 break;
     670             :         }
     671      159133 :         if (rc == -1)
     672             :         {
     673           0 :                 ELEKTRA_PLUGIN_FUNCTION (freeHandle) (handle);
     674           0 :                 return NULL;
     675             :         }
     676             :         return handle;
     677             : }

Generated by: LCOV version 1.13