static char *parseLine(char *origLine, char delim, unsigned long offset, Key *parentKey, unsigned long lineNr)
{
    char *line = (origLine + offset);
    if(*line == '\0')
        return NULL;
    char *ptr = strchr(line, delim);

    if(ptr == NULL)
    {
        ssize_t len = elektraStrLen(line);
        if(line[len-2] == '\n')
        {
            line[len-2] = '\0';
        }
        else if(line[len-1] == '\0')
        {
            ELEKTRA_ADD_WARNINGF(136, parentKey, "Unexpected end of line(%lu) , expected \\n, got \\0 \n %s\n", lineNr, origLine);
        }
        else if(line[len-2] == '\r')
        {
            ELEKTRA_ADD_WARNINGF(136, parentKey, "Unexpected end of line(%lu) , expected \\n, found \\r \n %s\n", lineNr, origLine);
            line[len-2] = '\0';
        }
        else
        {
            ELEKTRA_ADD_WARNINGF(136, parentKey, "Unexpected end of line(%lu) , expected \\n, but got 0x%x \n %s\n", lineNr, line[len-2], origLine);

        }
    }
    else
    {
        *ptr = '\0';
    }
    return line;
}
示例#2
0
static int elektraResolveMapperUser (ElektraResolved * handle, ElektraResolveTempfile tmpDir, Key * warningsKey)
{
	int finished = 0;
	size_t i;
	for (i = 0; !finished && i < sizeof (ELEKTRA_VARIANT_USER); ++i)
	{
		finished = elektraResolveUser (ELEKTRA_VARIANT_USER[i], handle, warningsKey);
	}
	if (finished == -1)
	{
		ELEKTRA_ADD_WARNINGF (83, warningsKey, "user resolver failed at step %zu, the configuration is: %s", i,
				      ELEKTRA_VARIANT_USER);
		return -1;
	}

	if (!(handle->dirname))
	{
		ELEKTRA_ADD_WARNINGF (83, warningsKey, "no resolver set the user dirname, the configuration is: %s", ELEKTRA_VARIANT_USER);
		return -1;
	}

	elektraResolveFinishByDirname (handle, tmpDir);

	return finished;
}
示例#3
0
/**
 * @brief sets mountpoint
 *
 * @param backend where the mountpoint should be set
 * @param elektraConfig the config where the mountpoint can be found
 * @param [out] errorKey the name also has the mountpoint set
 *
 * @pre ksCurrent() is root key
 * @post ksCurrent() is root key
 *
 * @retval -1 if no mountpoint is found or memory allocation problem
 * @retval 0 on success
 */
int elektraBackendSetMountpoint(Backend *backend, KeySet *elektraConfig, Key *errorKey)
{
	Key * root = ksCurrent(elektraConfig);
	Key * searchMountpoint = keyDup(root);
	keyAddBaseName(searchMountpoint, "mountpoint");
	Key * foundMountpoint = ksLookup(elektraConfig, searchMountpoint, 0);
	keyDel (searchMountpoint);
	ksLookup(elektraConfig, root, 0); // reset ksCurrent()

	if (!foundMountpoint)
	{
		ELEKTRA_ADD_WARNINGF(14, errorKey,
			"Could not find mountpoint within root %s",
			keyName(root));
		return -1;
	}

	backend->mountpoint = keyNew("",
			KEY_VALUE, keyBaseName(root), KEY_END);
	elektraKeySetName(backend->mountpoint, keyString(foundMountpoint),
			KEY_CASCADING_NAME | KEY_EMPTY_NAME);

	keySetName(errorKey, keyName(backend->mountpoint));

	if (!backend->mountpoint)
	{
		ELEKTRA_ADD_WARNINGF(14, errorKey,
			"Could not create mountpoint with name %s and value %s",
			keyString(foundMountpoint), keyBaseName(root));
		return -1;
	}

	keyIncRef(backend->mountpoint);
	return 0;
}
示例#4
0
static int handleMissingConflict (Key * parentKey, Key * key, Key * conflictMeta, OnConflict onConflict)
{
	int ret = 0;
	const char * problemKeys = elektraMetaArrayToString (key, keyName (conflictMeta), ", ");
	switch (onConflict)
	{
	case ERROR:
		ELEKTRA_SET_ERRORF (142, parentKey, "%s has missing subkeys: %s\n", keyName (key), problemKeys);
		ret = -1;
		break;
	case WARNING:
		ELEKTRA_ADD_WARNINGF (143, parentKey, "%s has missing subkeys: %s\n", keyName (key), problemKeys);
		break;
	case INFO:
	{
		const char * infoString = "has missing subkeys:";
		const size_t len = elektraStrLen (infoString) + elektraStrLen (problemKeys) + elektraStrLen (keyName (key));
		char * buffer = elektraMalloc (len);
		snprintf (buffer, len, "%s %s %s", keyName (key), infoString, problemKeys);
		elektraMetaArrayAdd (key, "logs/spec/info", buffer);
		elektraFree (buffer);
	}
	break;
	case IGNORE:

		break;
	}
	if (problemKeys)
	{
		elektraFree ((void *) problemKeys);
	}
	return ret;
}
示例#5
0
static int handleOutOfRangeConflict (Key * parentKey, Key * key, Key * specKey, Key * conflictMeta, OnConflict onConflict)
{
	int ret = 0;
	switch (onConflict)
	{
	case ERROR:
		ELEKTRA_SET_ERRORF (142, parentKey, "%s has invalid number of members: %s. Expected: %s\n", keyName (key),
				    keyString (conflictMeta), keyString (keyGetMeta (specKey, "array")));
		ret = -1;
		break;
	case WARNING:
		ELEKTRA_ADD_WARNINGF (143, parentKey, "%s has invalid number of members: %s. Expected: %s\n", keyName (key),
				      keyString (conflictMeta), keyString (keyGetMeta (specKey, "array")));
		break;
	case INFO:
	{
		const char * infoString = "%s has invalid number of member: %s. Expected: %s";
		const size_t len = elektraStrLen (infoString) + elektraStrLen (keyName (key)) + MAX_CHARS_IN_LONG +
				   keyGetValueSize (keyGetMeta (specKey, "array")) - 2;
		char * buffer = elektraMalloc (len);
		snprintf (buffer, len, infoString, keyName (key), keyString (conflictMeta), keyString (keyGetMeta (specKey, "array")));
		elektraMetaArrayAdd (key, "logs/spec/info", buffer);
		elektraFree (buffer);
	}
	break;
	case IGNORE:

		break;
	}
	return ret;
}
示例#6
0
static int handleInvalidConflict (Key * parentKey, Key * key, OnConflict onConflict)
{
	int ret = 0;
	switch (onConflict)
	{
	case ERROR:
		ELEKTRA_SET_ERRORF (142, parentKey, "Invalid key %s\n", keyName (key));
		ret = -1;
		break;
	case WARNING:
		ELEKTRA_ADD_WARNINGF (143, parentKey, "Invalid key %s\n", keyName (key));
		break;
	case INFO:
	{
		const char * infoString = "Invalid key ";
		const size_t len = elektraStrLen (infoString) + elektraStrLen (keyName (key)) - 1;
		char * buffer = elektraMalloc (len);
		snprintf (buffer, len, "Invalid key %s\n", keyName (key));
		elektraMetaArrayAdd (key, "logs/spec/info", buffer);
		elektraFree (buffer);
	}
	break;
	case IGNORE:

		break;
	}
	return ret;
}
示例#7
0
static int fcryptGpgCallAndCleanup (Key * parentKey, KeySet * pluginConfig, char ** argv, int argc, int tmpFileFd, char * tmpFile)
{
	int parentKeyFd = -1;
	int result = ELEKTRA_PLUGIN_FUNCTION (gpgCall) (pluginConfig, parentKey, NULL, argv, argc);

	if (result == 1)
	{
		parentKeyFd = open (keyString (parentKey), O_WRONLY);

		// gpg call returned success, overwrite the original file with the gpg payload data
		if (rename (tmpFile, keyString (parentKey)) != 0)
		{
			ELEKTRA_SET_ERRORF (31, parentKey, "Renaming file %s to %s failed.", tmpFile, keyString (parentKey));
			result = -1;
		}
	}

	if (result == 1)
	{
		if (parentKeyFd >= 0)
		{
			shredTemporaryFile (parentKeyFd, parentKey);
		}
	}
	else
	{
		// if anything went wrong above the temporary file is shredded and removed
		shredTemporaryFile (tmpFileFd, parentKey);
		if (unlink (tmpFile))
		{
			ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_FCRYPT_UNLINK, parentKey, "Affected file: %s, error description: %s", tmpFile,
					      strerror (errno));
		}
	}

	if (parentKeyFd >= 0 && close (parentKeyFd))
	{
		ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_FCRYPT_CLOSE, parentKey, "%s", strerror (errno));
	}
	if (close (tmpFileFd))
	{
		ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_FCRYPT_CLOSE, parentKey, "%s", strerror (errno));
	}
	elektraFree (tmpFile);
	return result;
}
示例#8
0
static int elektraResolveSystemXDG(resolverHandle *p,
		Key *warningsKey)
{
	const char * configDir = getenv("XDG_CONFIG_DIRS");
	const char *defaultDir = "/etc/xdg";

	if (!configDir || !strcmp(configDir, ""))
	{
		elektraResolveSystemXDGHelper(p, defaultDir);
		elektraResolveFinishByFilename(p);
		return 1;
	}

	char *saveptr = 0;
	char *str = elektraStrDup(configDir);
	char *result = strtok_r (str, ":", &saveptr);
	struct stat buf;
	int errnoSave = errno;
	int success = 0;
	while (result)
	{
		if (result[0] != '/')
		{
			ELEKTRA_ADD_WARNINGF(100,
				warningsKey,
				"XDG_CONFIG_DIRS contains a path that is "
				"not absolute (violates XDG specification) and thus "
			 	"it was skipped: %s",
				result);

			result = strtok_r (0, ":", &saveptr);
			continue;
		}

		success = 1; // at least once we got a valid path

		elektraResolveSystemXDGHelper(p, result);

		if (stat(p->filename, &buf) == 0)
		{
			// we found a file!
			break;
		}

		result = strtok_r (0, ":", &saveptr);
	}
	elektraFree(str);
	errno = errnoSave;

	if (!success)
	{
		elektraResolveSystemXDGHelper(p, defaultDir);
	}

	elektraResolveFinishByFilename(p);
	return 1;
}
示例#9
0
/**
 * @return freshly allocated buffer with current working directory
 *
 * @param warningsKey where warnings are added
 */
static char * elektraGetCwd (Key * warningsKey)
{
	int size = 4096;
	char * cwd = elektraMalloc (size);
	if (cwd == NULL)
	{
		ELEKTRA_ADD_WARNING (83, warningsKey, "could not alloc for getcwd, defaulting to /");
		return 0;
	}

	char * ret = NULL;
	while (ret == NULL)
	{
		ret = getcwd (cwd, size);

		if (ret == NULL)
		{
			if (errno != ERANGE)
			{
				// give up, we cannot handle the problem
				elektraFree (cwd);
				ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_NOCWD, warningsKey,
						      "getcwd failed with errno %d \"%s\", defaulting to /", errno, strerror (errno));
				return 0;
			}

			// try to double the space
			size *= 2;
			elektraRealloc ((void **) &cwd, size);
			if (cwd == NULL)
			{
				ELEKTRA_ADD_WARNINGF (83, warningsKey, "could not realloc for getcwd size %d, defaulting to /", size);
				return 0;
			}
		}
	}

	return ret;
}
示例#10
0
static void elektraResolveDir (resolverHandle * p, Key * warningsKey)
{
	p->filename = elektraMalloc (KDB_MAX_PATH_LENGTH);

#if defined(_WIN32)
	CHAR dir[MAX_PATH];
	DWORD dwRet = GetCurrentDirectory (MAX_PATH, dir);
	if (dwRet == 0)
	{
		char buf[256];
		FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256,
			       NULL);
		ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_NOCWD, warningsKey, "GetCurrentDirectory failed: %s, defaulting to /", buf);
		dir[0] = 0;
	}
	else if (dwRet > MAX_PATH)
	{
		ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_NOCWD, warningsKey, "GetCurrentDirectory failed, buffer size too small, needed: %ld",
				      dwRet);
		dir[0] = 0;
	}
	escapePath (dir);
#else
	char dir[KDB_MAX_PATH_LENGTH];
	if (getcwd (dir, KDB_MAX_PATH_LENGTH) == 0)
	{
		ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_NOCWD, warningsKey, "getcwd failed: %s, defaulting to /", strerror (errno));
		dir[0] = 0;
	}
#endif

	strcpy (p->filename, dir);
	strcat (p->filename, "/");
	strncat (p->filename, p->path, KDB_MAX_PATH_LENGTH - strlen (dir) - 3);
	p->filename[KDB_MAX_PATH_LENGTH - 1] = 0;

	return;
}
示例#11
0
static int elektraResolveMapperSystem (ElektraResolved * handle, ElektraResolveTempfile tmpDir, Key * warningsKey)
{
	int finished = 0;
	size_t i;
	for (i = 0; !finished && i < sizeof (ELEKTRA_VARIANT_SYSTEM); ++i)
	{
		finished = elektraResolveSystem (ELEKTRA_VARIANT_SYSTEM[i], handle, tmpDir, warningsKey);
	}
	if (finished == -1)
	{
		ELEKTRA_ADD_WARNINGF (83, warningsKey, "no resolver set the user dirname, the configuration is: %s", ELEKTRA_VARIANT_USER);
		return -1;
	}

	if (!(handle->fullPath))
	{
		ELEKTRA_ADD_WARNINGF (83, warningsKey, "no resolver set the system dirname, the configuration is: %s",
				      ELEKTRA_VARIANT_SYSTEM);
		return -1;
	}

	return finished;
}
示例#12
0
static int elektraResolveEnvHome (ElektraResolved * handle, Key * warningsKey)
{
	const char * home = getenv ("HOME");

	if (!home || !strcmp (home, ""))
	{
		return 0;
	}

	if (home[0] != '/')
	{
		ELEKTRA_ADD_WARNINGF (100, warningsKey,
				      "HOME contains a path that is "
				      "not absolute and thus "
				      "it was skipped: %s",
				      home);
		return 0;
	}
	elektraResolveUsingHome (handle, home, 1);
	return 1;
}
示例#13
0
static int elektraResolveUserXDGHome (ElektraResolved * handle, Key * warningsKey)
{
	const char * home = getenv ("XDG_CONFIG_HOME");

	if (!home || !strcmp (home, ""))
	{
		return 0;
	}

	if (home[0] != '/')
	{
		ELEKTRA_ADD_WARNINGF (100, warningsKey,
				      "XDG_CONFIG_HOME contains a path that is "
				      "not absolute (violates XDG specification) and thus "
				      "it was skipped: %s",
				      home);
		return 0;
	}
	elektraResolveUsingHome (handle, home, 0);
	return 1;
}
示例#14
0
文件: backend.c 项目: beku/libelektra
/**Builds a backend out of the configuration supplied
 * from:
 *
@verbatim
system/elektra/mountpoints/<name>
@endverbatim
 *
 * The root key must be like the above example. You do
 * not need to rewind the keyset. But every key must be
 * below the root key.
 *
 * The internal consistency will be checked in this
 * function. If necessary parts are missing, like
 * no plugins, they cant be loaded or similar 0
 * will be returned.
 *
 * ksCut() is perfectly suitable for cutting out the
 * configuration like needed.
 *
 * @note The given KeySet will be deleted within the function,
 * don't use it afterwards.
 *
 * @param elektraConfig the configuration to work with.
 *        It is used to build up this backend.
 * @param modules used to load new modules or get references
 *        to existing one
 * @return a pointer to a freshly allocated backend
 *         this could be the requested backend or a so called
 *         "missing backend".
 * @retval 0 if out of memory
 * @ingroup backend
 */
Backend* elektraBackendOpen(KeySet *elektraConfig, KeySet *modules, Key *errorKey)
{
	Key * cur;
	Key * root;
	KeySet *referencePlugins = 0;
	KeySet *systemConfig = 0;
	int failure = 0;

	referencePlugins = ksNew(0, KS_END);
	ksRewind(elektraConfig);

	root = ksNext (elektraConfig);

	Backend *backend = elektraBackendAllocate();

	while ((cur = ksNext(elektraConfig)) != 0)
	{
		if (keyRel (root, cur) == 1)
		{
			// direct below root key
			KeySet *cut = ksCut (elektraConfig, cur);
			if (!strcmp(keyBaseName(cur), "config"))
			{
				systemConfig = elektraRenameKeys(cut, "system");
				ksDel (cut);
			}
			else if (!strcmp(keyBaseName(cur), "getplugins"))
			{
				if (elektraProcessPlugins(backend->getplugins, modules, referencePlugins,
							cut, systemConfig, errorKey) == -1)
				{
					if (!failure) ELEKTRA_ADD_WARNING(13, errorKey, "elektraProcessPlugins for get failed");
					failure = 1;
				}
			}
			else if (!strcmp(keyBaseName(cur), "mountpoint"))
			{
				backend->mountpoint = keyNew("",
						KEY_VALUE, keyBaseName(root), KEY_END);
				elektraKeySetName(backend->mountpoint, keyString(cur),
						KEY_CASCADING_NAME | KEY_EMPTY_NAME);

				if (!backend->mountpoint)
				{
					if (!failure) ELEKTRA_ADD_WARNINGF(14, errorKey,
						"Could not create mountpoint with name %s and value %s",
						keyString(cur), keyBaseName(root));
					failure = 1;
				}

				keyIncRef(backend->mountpoint);
				ksDel (cut);
			}
			else if (!strcmp(keyBaseName(cur), "setplugins"))
			{
				if (elektraProcessPlugins(backend->setplugins, modules, referencePlugins,
							cut, systemConfig, errorKey) == -1)
				{
					if (!failure) ELEKTRA_ADD_WARNING(15, errorKey, "elektraProcessPlugins for set failed");
					failure = 1;
				}
			}
			else if (!strcmp(keyBaseName(cur), "errorplugins"))
			{
				if (elektraProcessPlugins(backend->errorplugins, modules, referencePlugins,
							cut, systemConfig, errorKey) == -1)
				{
					if (!failure) ELEKTRA_ADD_WARNING(15, errorKey, "elektraProcessPlugins for error failed");
					failure = 1;
				}
			} else {
				// no one cares about that config
				if (!failure) ELEKTRA_ADD_WARNING(16, errorKey, keyBaseName(cur));
				ksDel (cut);
			}
		}
	}

	if (failure)
	{
		Backend *tmpBackend = elektraBackendOpenMissing(backend->mountpoint);
		elektraBackendClose(backend, errorKey);
		backend = tmpBackend;
	}

	ksDel (systemConfig);
	ksDel (elektraConfig);
	ksDel (referencePlugins);

	return backend;
}
示例#15
0
/**
 * @brief decrypt the file specified at parentKey
 * @param pluginConfig holds the plugin configuration
 * @param parentKey holds the path to the file to be encrypted. Will hold an error description in case of failure.
 * @param state holds the plugin state
 * @retval 1 on success
 * @retval -1 on error, errorKey holds an error description
 */
static int fcryptDecrypt (KeySet * pluginConfig, Key * parentKey, fcryptState * state)
{
	int tmpFileFd = -1;
	char * tmpFile = getTemporaryFileName (pluginConfig, keyString (parentKey), &tmpFileFd);
	if (!tmpFile)
	{
		ELEKTRA_SET_ERROR (87, parentKey, "Memory allocation failed");
		return -1;
	}

	const size_t testMode = inTestMode (pluginConfig);

	// prepare argument vector for gpg call
	// 8 static arguments (magic number below) are:
	//   1. path to the binary
	//   2. --batch
	//   3. -o
	//   4. path to tmp file
	//   5. yes
	//   6. -d
	//   7. file to be encrypted
	//   8. NULL terminator
	int argc = 8 + (2 * testMode);
	char * argv[argc];
	int i = 0;

	argv[i++] = NULL;
	argv[i++] = "--batch";
	argv[i++] = "--yes";

	// if we are in test mode we add the trust model
	if (testMode)
	{
		argv[i++] = "--trust-model";
		argv[i++] = "always";
	}

	argv[i++] = "-o";
	argv[i++] = tmpFile;
	argv[i++] = "-d";
	// safely discarding const from keyString() return value
	argv[i++] = (char *) keyString (parentKey);
	argv[i++] = NULL;

	// NOTE the decryption process works like this:
	// gpg2 --batch --yes -o tmpfile -d configFile
	int result = ELEKTRA_PLUGIN_FUNCTION (gpgCall) (pluginConfig, parentKey, NULL, argv, argc);
	if (result == 1)
	{
		state->originalFilePath = elektraStrDup (keyString (parentKey));
		state->tmpFilePath = tmpFile;
		state->tmpFileFd = tmpFileFd;
		keySetString (parentKey, tmpFile);
	}
	else
	{
		// if anything went wrong above the temporary file is shredded and removed
		shredTemporaryFile (tmpFileFd, parentKey);
		if (unlink (tmpFile))
		{
			ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_FCRYPT_UNLINK, parentKey, "Affected file: %s, error description: %s", tmpFile,
					      strerror (errno));
		}
		if (close (tmpFileFd))
		{
			ELEKTRA_ADD_WARNINGF (ELEKTRA_WARNING_FCRYPT_CLOSE, parentKey, "%s", strerror (errno));
		}
		elektraFree (tmpFile);
	}
	return result;
}
示例#16
0
static int csvRead(KeySet *returned, Key *parentKey, char delim, short useHeader, unsigned long fixColumnCount, const char **colNames)
{
    const char *fileName;
    fileName = keyString(parentKey);
    FILE *fp = NULL;
    fp = fopen(fileName, "rb");
    if(!fp)
    {
        ELEKTRA_SET_ERRORF(116, parentKey, "couldn't open file %s\n", fileName);
        return -1;
    }

    unsigned long length = 0;
    length = getLineLength(fp);
    if(length == 0)
    {
        ELEKTRA_ADD_WARNING(118, parentKey, "Empty file");
        fclose(fp);
        return -2;
    }

    char *lineBuffer;
    lineBuffer = elektraMalloc((length * sizeof(char))+1);
    if(!lineBuffer)
    {
        ELEKTRA_SET_ERROR(87, parentKey, "Out of memory");
        return -1;
    }
    if(!fgets(lineBuffer, length, fp))
    {
        ELEKTRA_SET_ERROR(116, parentKey, "Cant read from file");
        return -1;
    }

    unsigned long columns = 0;
    columns = getColumnCount(lineBuffer, delim);
    if(fixColumnCount)
    {
        if(columns != fixColumnCount)
        {
            ELEKTRA_SET_ERROR(117, parentKey, "illegal number of columns in Header line");
            elektraFree(lineBuffer);
            fclose(fp);
            return -1;
        }
    }
    unsigned long colCounter = 0;
    unsigned long lineCounter = 0;
    unsigned long offset = 0;
    char *col;
    char buf[INTSTR_MAX];
    int nr_keys = 1;
    KeySet *header = ksNew(0, KS_END);
    Key *key;

    if(useHeader == 1)
    {
        colCounter = 0;
        offset = 0;
        while((col = parseLine(lineBuffer, delim, offset, parentKey, lineCounter)) != NULL)
        {
            offset += elektraStrLen(col);
            key = keyDup(parentKey);
            if(colNames && (colNames+colCounter))
            {
                keyAddBaseName(key, colNames[colCounter]);
            }
            else
            {
                keyAddBaseName(key, col);
            }
            keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1));
            ksAppendKey(header, key);
            ++colCounter;
        }
        fseek(fp, 0, SEEK_SET);
    }
    else
    {
        colCounter = 0;
        //if no headerline exists name the columns 0..N where N is the number of columns
        key = keyDup(parentKey);
        keyAddName(key, "#");
        while(colCounter < columns)
        {
            if(elektraArrayIncName(key) == -1)
            {
                elektraFree(lineBuffer);
                keyDel(key);
                ksDel(header);
                fclose(fp);
                return -1;
            }
            keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1));
            if(colNames && (colNames+colCounter))
                keySetBaseName(key, colNames[colCounter]);
            ksAppendKey(header, keyDup(key));
            ++colCounter;
        }
        keyDel(key);
        if(useHeader == 0)
            fseek(fp, 0, SEEK_SET);
    }
    Key *dirKey;
    Key *cur;
    dirKey = keyDup(parentKey);
    keyAddName(dirKey, "#");
    while(!feof(fp))
    {
        length = getLineLength(fp);
        if(length == 0)
            break;
        if(elektraRealloc((void **)&lineBuffer, (length * sizeof(char))+1) < 0)
        {
            fclose(fp);
            elektraFree(lineBuffer);
            ksDel(header);
            keyDel(dirKey);
            ELEKTRA_SET_ERROR(87, parentKey, "Out of memory");
            return -1;
        }
        fgets(lineBuffer, length, fp);
        if(elektraArrayIncName(dirKey) == -1)
        {
            elektraFree(lineBuffer);
            keyDel(dirKey);
            ksDel(header);
            fclose(fp);
            return -1;
        }
        ++nr_keys;
        offset = 0;
        colCounter = 0;
        char *lastIndex = "#0";
        while((col = parseLine(lineBuffer, delim, offset, parentKey, lineCounter)) != NULL)
        {
            cur = getKeyByOrderNr(header, colCounter);
            offset += elektraStrLen(col);
            key = keyDup(dirKey);
            keyAddBaseName(key, keyBaseName(cur));
            keySetString(key, col);
            keySetMeta(key, "csv/order", itostr(buf, colCounter, sizeof(buf)-1));
            ksAppendKey(returned, key);
            lastIndex = (char *)keyBaseName(key);
            ++nr_keys;
            ++colCounter;
        }
        keySetString(dirKey, lastIndex);
        ksAppendKey(returned, keyDup(dirKey));
        if(colCounter != columns)
        {
            if(fixColumnCount)
            {
                ELEKTRA_SET_ERRORF(117, parentKey, "illegal number of columns in line %lu", lineCounter);
                elektraFree(lineBuffer);
                fclose(fp);
                keyDel(dirKey);
                ksDel(header);
                return -1;
            }
            ELEKTRA_ADD_WARNINGF(118, parentKey, "illegal number of columns in line %lu", lineCounter);
        }
        ++lineCounter;
    }
    key = keyDup(parentKey);
    keySetString(key, keyBaseName(dirKey));
    ksAppendKey(returned, key);
    keyDel(dirKey);
    fclose(fp);
    elektraFree(lineBuffer);
    ksDel(header);
    return 1;
}