Exemplo n.º 1
0
/**
 * @brief Close all levels in cur not needed in next
 *
 * Closing is much simpler then opening because no names need to be
 * yield.
 *
 * @pre keys are not allowed to be below,
 *      except: last run where everything below root/parent key is
 *      closed
 *
 * Then all levels are reverse iterated until the level before the equal
 * level.
 * @see elektraGenCloseIterate
 *
 * In the level before the equal level there is some special handling in
 * regards to the next level.
 * @see elektraGenCloseFirst
 *
 * @example
 *
 * cur:  user/sw/org/deeper
 * next: user/sw/org/other/deeper/below
 * -> nothing will be done ("deeper" is value)
 * [eq: 3, cur: 4, next: 6, gen: 0]
 *
 * cur:  user/sw/org/other/deeper/below
 * next: user/no
 * -> "deeper", "other", "org" and "sw" maps will be closed ("below" is value)
 * [eq: 1, cur: 6, next: 2, gen: 4]
 *
 * cur:  user/no
 * next: user/oops/it/is/below
 * -> nothing will be done ("no" is value)
 * [eq: 1, cur: 2, next: 5, gen: 0]
 *
 * cur:  user/oops/it/is/below
 * next: user/x/t/s/x
 * -> close "is", "it", "oops"
 * [eq: 1, cur: 5, next: 5, gen: 3]
 *
 * last iteration (e.g. close down to root)
 * cur:  user/x/t/s/x
 * next: user
 * -> close "s", "t" and "x" maps
 * [eq: 1, cur: 5, next: 1, gen: 3]
 *
 * cur:  user/#0/1/1/1
 * next: user/#1/1/1/1
 * -> close "1", "1", "1", but not array
 * [eq: 1, cur: 5, next: 5, gen: 3]
 *
 * @param g
 * @param cur
 * @param next
 */
void elektraGenClose (yajl_gen g, const Key * cur, const Key * next)
{
	int curLevels = elektraKeyCountLevel (cur);
#ifdef ELEKTRA_YAJL_VERBOSE
	int nextLevels = elektraKeyCountLevel (next);
#endif
	int equalLevels = elektraKeyCountEqualLevel (cur, next);

	// 1 for last level not to iterate, 1 before 1 after equal
	int levels = curLevels - equalLevels - 2;

	const char * pcur = keyName (cur);
	size_t csize = 0;
	const char * pnext = keyName (next);
	size_t nsize = 0;
	for (int i = 0; i < equalLevels + 1; ++i)
	{
		pcur = keyNameGetOneLevel (pcur + csize, &csize);
		pnext = keyNameGetOneLevel (pnext + nsize, &nsize);
	}

#ifdef ELEKTRA_YAJL_VERBOSE
	printf ("elektraGenClose, eq: %d, cur: %s %d, next: %s %d, "
		"levels: %d\n",
		equalLevels, pcur, curLevels, pnext, nextLevels, levels);
#endif

	if (levels > 0)
	{
		elektraGenCloseLast (g, cur);
	}
	elektraGenCloseIterate (g, cur, levels);
	elektraGenCloseFirst (g, pcur, csize, pnext, levels);
}
Exemplo n.º 2
0
/**
 * @brief Close the last element
 *
 * Needs less special handling because cur is fully below next.
 *
 * Will fully iterate over all elements.
 *
 * @param g handle to yield close events
 * @param cur current key
 * @param next the last key (the parentKey)
 */
void elektraGenCloseFinally(yajl_gen g, const Key *cur, const Key *next)
{
    int curLevels = elektraKeyCountLevel(cur);
#ifdef ELEKTRA_YAJL_VERBOSE
    int nextLevels = elektraKeyCountLevel(next);
#endif
    int equalLevels = elektraKeyCountEqualLevel(cur, next);

    // 1 for last level not to iterate, 1 after equal
    int levels = curLevels - equalLevels - 1;

    const char *pcur = keyName(cur);
    size_t csize = 0;
    const char *pnext = keyName(next);
    size_t nsize = 0;
    for (int i=0; i < equalLevels+1; ++i)
    {
        pcur=keyNameGetOneLevel(pcur+csize,&csize);
        pnext=keyNameGetOneLevel(pnext+nsize, &nsize);
    }

#ifdef ELEKTRA_YAJL_VERBOSE
    printf ("elektraGenFinally, eq: %d, cur: %s %d, next: %s %d, "
            "levels: %d\n",
            equalLevels,
            pcur, curLevels,
            pnext, nextLevels,
            levels);
#endif
    // fixes elektraGenCloseIterate for the special handling of
    // arrays finally
    elektraGenCloseLast(g, cur);

    // now we iterate over the middle part
    elektraGenCloseIterate(g, cur, levels);

    // now we look at the first unequal element
    // this is the very last element we are about to close
    if (pcur && *pcur == '#')
    {
#ifdef ELEKTRA_YAJL_VERBOSE
        printf ("array close FINAL\n");
#endif
    }
    else
    {
#ifdef ELEKTRA_YAJL_VERBOSE
        printf ("GEN map close FINAL\n");
#endif
        yajl_gen_map_close(g);
    }


}
Exemplo n.º 3
0
/**
 * @brief Add an already escaped name to the keyname.
 *
 * The same way as in keySetName() this method finds the canonical pathname:
 * - it will ignore /./
 * - it will remove a level when /../ is used
 * - it will remove multiple slashes ////
 *
 * For example:
 * @snippet keyName.c add name
 *
 * Unlike keySetName() it adds relative to the previous name and
 * cannot change the namespace of a key.
 * For example:
 * @snippet keyName.c namespace
 *
 * The passed name needs to be valid according the @link keyname key name rules @endlink.
 * It is not allowed to:
 * - be empty
 * - end with unequal number of \\
 *
 * @param key the key where a name should be added
 * @param newName the new name to append
 *
 * @since 0.8.11
 *
 * @retval size of the new key
 * @retval -1 if key is a null pointer or did not have a valid name before
 * @retval -1 if newName is not a valid escaped name
 * @retval -1 on allocation errors
 * @retval -1 if key was inserted to a keyset before
 * @retval 0 if nothing was done because newName had only slashes, is too short, is empty or is null
 * @ingroup keyname
 */
ssize_t keyAddName (Key * key, const char * newName)
{
	if (!key) return -1;
	if (test_bit (key->flags, KEY_FLAG_RO_NAME)) return -1;
	if (!key->key) return -1;
	if (!strcmp (key->key, "")) return -1;
	if (!newName) return 0;
	size_t const nameSize = elektraStrLen (newName);
	if (nameSize < 2) return 0;
	if (!elektraValidateKeyName (newName, nameSize)) return -1;

	const size_t origSize = key->keySize;
	const size_t newSize = origSize + nameSize;
	elektraRealloc ((void **)&key->key, newSize * 2);
	if (!key->key) return -1;

	size_t size = 0;
	const char * p = newName;
	int avoidSlash = 0;

	if (*key->key == '/') avoidSlash = key->keySize == 2;

	--key->keySize; // loop assumes that key->key[key->keySize] is last character and not NULL

	/* iterate over each single folder name removing repeated '/', .  and .. */
	while (*(p = keyNameGetOneLevel (p + size, &size)))
	{
		if (size == 1 && strncmp (p, ".", 1) == 0)
		{
			continue; /* just ignore current directory */
		}
		else if (size == 2 && strncmp (p, "..", 2) == 0) /* give away one level*/
		{
			elektraRemoveOneLevel (key, &avoidSlash);
			continue;
		}

		if (!avoidSlash)
		{
			/* Add a '/' to the end of key name */
			key->key[key->keySize] = KDB_PATH_SEPARATOR;
			key->keySize++;
		}
		else
		{
			avoidSlash = 0;
		}

		/* carefully append basenames */
		char * d = key->key + key->keySize;
		memcpy (d, p, size);
		key->keySize += size;
	}

	++key->keySize; /*for \\0 ending*/

	elektraFinalizeName (key);

	return origSize == key->keySize ? 0 : key->keySize;
}
Exemplo n.º 4
0
/**
 * @internal
 *
 * @brief Used by keyAddName
 *
 * Will remove one level of key, even if key->key is not null terminated
 * also handles cascading keys and sets avoidSlash properly.
 *
 * @param key to remove one level
 * @param [out] avoidSlash set to 1 if / is already present (cascading)
 */
static void elektraRemoveOneLevel (Key * key, int * avoidSlash)
{
	int levels = 0;
	char * x = key->key;
	size_t xsize = 0;
	size_t sizeOfLastLevel = 0;
	char * const last = &key->key[key->keySize];
	const char save = *last;
	*last = 0;

	while (*(x = keyNameGetOneLevel (x + xsize, &xsize)))
	{
		sizeOfLastLevel = xsize;
		levels++;
	}

	if (levels > 1)
	{
		key->keySize -= sizeOfLastLevel + 1;
		key->key[key->keySize] = 0;
	}
	else if (*key->key == '/') // cascading key
	{
		// strip down to root
		key->keySize = 1;
		*avoidSlash = 1;
	}
	*last = save;
}
Exemplo n.º 5
0
/**
 * @internal
 *
 * @brief Unescapes a key name.
 *
 * Writes a null terminated sequence of key name parts to dest.
 *
 * May only need half the storage than the source string.
 * It is not safe to use the same string for source and dest.
 **/
size_t elektraUnescapeKeyName (const char * source, char * dest)
{
	const char * sp = source;
	char * dp = dest;
	size_t size = 0;

	ELEKTRA_ASSERT (sp != NULL && dp != NULL, "Got null pointer sp: %p dp: %p", (void *) sp, (void *) dp);

	if (*sp == '/')
	{
		// handling for cascading names
		*dp = 0;
		++dp;
	}
	while (*(sp = keyNameGetOneLevel (sp + size, &size)))
	{
		if (!elektraUnescapeKeyNamePartBegin (sp, size, &dp))
		{
			dp = elektraUnescapeKeyNamePart (sp, size, dp);
		}
		*dp = 0;
		++dp;
	}
	return dp - dest;
}
Exemplo n.º 6
0
static void test_keyNameGetOneLevel (void)
{
	printf ("test keyNameGetOneLevel\n");

	size_t size = 0;
	char buffer[] = "a\\/\\/def";
	char * p = keyNameGetOneLevel (buffer, &size);
	succeed_if (p == buffer, "p not at start of buffer");
	succeed_if (size == sizeof (buffer) - 1, "size not set correctly");
}
Exemplo n.º 7
0
/**
 * Sets @c baseName as the new basename for @c key.
 *
 * Only the baseName will be affected and no other part of the key.
 *
 * All text after the last @c '/' in the @p key keyname is erased and
 * @p baseName is appended.
 *
 * So let us suppose @p key has name @c "system/dir1/dir2/key1". If @p baseName
 * is @c "key2", the resulting key name will be @c "system/dir1/dir2/key2".
 * If @p baseName is empty or NULL, the resulting key name will
 * be @c "system/dir1/dir2".
 *
 * This function does proper escaping on the supplied name argument.
 *
 * You can use all names to set as basename (e.g. . (dot), ..
 * (dot-dot), % and "" (empty)). They will be properly escaped.
 *
 * A simple example is:
 * @snippet basename.c set base basic
 *
 * If you want to add and not change the basename, use keyAddBaseName()
 * instead. If you do not want escaping, use keyAddName() instead.
 *
 * To add an inactive key name, use:
 * @snippet testabi_key.c base1
 *
 * When you want to add an array item, use:
 * @snippet testabi_key.c base2
 *
 * @see keyname for more details on special names
 *
 * @param key the key object to work with
 * @param baseName the string used to overwrite the basename of the key
 * @return the size in bytes of the new key name
 * @retval -1 on NULL pointers
 * @retval -1 if key was inserted to a keyset before
 * @see keyAddBaseName()
 * @see keySetName() to set a new name
 * @ingroup keyname
 */
ssize_t keySetBaseName(Key *key, const char *baseName)
{
	if (!key) return -1;
	if (test_bit(key->flags,  KEY_FLAG_RO_NAME)) return -1;
	if (!key->key) return -1;

	size_t size=0;
	char *searchBaseName=0;
	size_t searchBaseSize=0;
	char *p = key->key;

	while (*(p=keyNameGetOneLevel(p+size,&size)))
	{
		searchBaseName=p;
		searchBaseSize=size+1;
	}

	if (!searchBaseName || searchBaseName==key->key)
	{
		return -1;
	}

	// truncate the key
	key->keySize -= searchBaseSize;

	if (!baseName)
	{
		// just remove base name, so we are finished
		elektraFinalizeName(key);
		return key->keySize;
	}

	char *escaped = elektraMalloc (strlen (baseName) * 2 + 2);
	elektraEscapeKeyNamePart(baseName, escaped);
	size_t sizeEscaped = elektraStrLen (escaped);

	elektraRealloc((void**)&key->key, (key->keySize+sizeEscaped)*2);
	if (!key->key)
	{
		elektraFree (escaped);
		return -1;
	}

	key->key [key->keySize - 1] = KDB_PATH_SEPARATOR;
	memcpy (key->key + key->keySize,
			escaped, sizeEscaped);

	elektraFree (escaped);

	key->keySize += sizeEscaped;
	elektraFinalizeName(key);

	return key->keySize;
}
Exemplo n.º 8
0
ssize_t elektraKeySetName(Key *key, const char *newName,
		option_t options)
{
	if (!key) return -1;
	if (test_bit(key->flags,  KEY_FLAG_RO_NAME)) return -1;

	elektraRemoveKeyName(key);
	if (!(options & KEY_META_NAME)) keySetOwner (key, NULL);

	switch (keyGetNameNamespace(newName))
	{
	case KEY_NS_NONE: ELEKTRA_ASSERT(0);
	case KEY_NS_EMPTY:
		elektraFinalizeEmptyName(key);
		return 0; // as documented
	case KEY_NS_CASCADING: key->keyUSize=1;key->keySize=sizeof("/"); break;
	case KEY_NS_SPEC: key->keyUSize=key->keySize=sizeof("spec"); break;
	case KEY_NS_PROC: key->keyUSize=key->keySize=sizeof("proc"); break;
	case KEY_NS_DIR: key->keyUSize=key->keySize=sizeof("dir"); break;
	case KEY_NS_USER: elektraHandleUserName(key, newName); break;
	case KEY_NS_SYSTEM: key->keyUSize=key->keySize=sizeof("system"); break;
	case KEY_NS_META:
		if (!(options & KEY_META_NAME)) return -1;
		keyNameGetOneLevel(newName,&key->keySize);
		key->keyUSize = ++ key->keySize; // for null
		break;
	} // Note that we abused keyUSize for cascading and user:owner

	const size_t length = elektraStrLen(newName);
	key->key=elektraMalloc(key->keySize*2);
	memcpy(key->key, newName, key->keySize);
	if (length == key->keyUSize || length == key->keySize)
	{	// use || because full length is keyUSize in user, but keySize for /
		// newName consisted of root only
		elektraFinalizeName(key);
		return key->keyUSize;
	}

	if (elektraOnlySlashes(newName+key->keyUSize-1))
	{
		elektraFinalizeName(key);
		return key->keySize;
	}

	key->key[key->keySize-1] = '\0';
	const ssize_t ret = keyAddName(key, newName+key->keyUSize);
	if (ret == -1) elektraRemoveKeyName(key);
	else return key->keySize;
	return ret;
}
Exemplo n.º 9
0
static void elektraHandleUserName (Key * key, const char * newName)
{
	const size_t userLength = sizeof ("user");
	key->keyUSize = key->keySize = userLength;

	const char delim = newName[userLength - 1];
	// no owner, we are finished
	if (delim == '/' || delim == '\0') return;
	ELEKTRA_ASSERT (delim == ':');

	// handle owner (compatibility, to be removed)
	keyNameGetOneLevel (newName, &key->keyUSize);
	const size_t ownerLength = key->keyUSize - userLength;
	++key->keyUSize;
	char * owner = elektraMalloc (ownerLength + 1);
	if (!owner) return; // out of memory, ok for owner
	strncpy (owner, newName + userLength, ownerLength);
	owner[ownerLength] = 0;
	keySetOwner (key, owner);
	elektraFree (owner);
}
Exemplo n.º 10
0
/**
 * Check whether a key is inactive.
 *
 * In Elektra terminology a hierarchy of keys is inactive if
 * the rootkey's basename starts with '.'. So a key is
 * also inactive if it is below an inactive key.
 * For example, user/key/.hidden is inactive and so
 * is user/.hidden/below.
 *
 * Inactive keys should not have any meaning to applications,
 * they are only a convention reserved for users and
 * administrators. To automatically remove all inactive keys
 * for an application, consider to use the hidden plugin.
 *
 * @param key the key object to work with
 * @retval 1 if the key is inactive
 * @retval 0 if the key is active
 * @retval -1 on NULL pointer or when key has no name
 * @ingroup keytest
 *
 */
int keyIsInactive (const Key * key)
{
	if (!key) return -1;

	const char * p = keyName (key);
	if (!p) return -1;
	if (p[0] == '\0') return -1;

	size_t size = 0;

	while (*(p = keyNameGetOneLevel (p + size, &size)))
	{
		if (size > 0)
		{
			if (p[0] == '.')
			{
				return 1;
			}
		}
	}

	return 0;
}
Exemplo n.º 11
0
int keyIsBelow (const Key * key, const Key * check)
{
	const char * keyname = 0;
	const char * checkname = 0;
	const char * ukeyname = 0;
	const char * ucheckname = 0;
	ssize_t keysize = 0;
	ssize_t checksize = 0;
	ssize_t ukeysize = 0;
	ssize_t uchecksize = 0;

	if (!key || !check) return -1;

	keyname = keyName (key);
	checkname = keyName (check);
	ukeyname = keyUnescapedName (key);
	ucheckname = keyUnescapedName (check);
	keysize = keyGetNameSize (key);
	checksize = keyGetNameSize (check);
	ukeysize = keyGetUnescapedNameSize (key);
	uchecksize = keyGetUnescapedNameSize (check);
	if (!strcmp (checkname, "/")) return 0;
	if (!strcmp (keyname, "/"))
	{
		if (checkname[0] == '/') return 1;
		if (strchr (checkname, '/')) return 1;
	}
	else if (checkname[0] == '/')
	{
		if (keyname[0] == '/')
		{
			if (!strncmp (keyname, checkname, keysize - 1))
			{
				if (ucheckname[ukeysize - 1] == '\0' && uchecksize > ukeysize)
				{
					return 1;
				}
			}
		}
		else
		{
			size_t size = 0;
			char * ptr = (char *)keyname;
			ptr = keyNameGetOneLevel (ptr, &size);
			if (size == (size_t)keysize)
			{
				return 1;
			}
			keyname += size;
			keysize = elektraStrLen (keyname);
			ptr = strrchr (ukeyname, '\0');
			ukeysize -= (ptr - ukeyname);
			if (!strncmp (keyname, checkname, keysize - 1))
			{
				if (ucheckname[ukeysize - 1] == '\0' && uchecksize > ukeysize)
				{
					return 1;
				}
			}
		}
	}
	else if (keyname[0] == '/')
	{
		size_t size = 0;
		char * ptr = (char *)checkname;
		ptr = keyNameGetOneLevel (ptr, &size);
		if (size == (size_t)checksize)
		{
			return 0;
		}
		checkname += size;
		checksize = elektraStrLen (checkname);
		ptr = strrchr (ucheckname, '\0');
		uchecksize -= (ptr - ucheckname);
		ucheckname = ptr;
		if (!strncmp (keyname, checkname, keysize - 1))
		{
			if (ucheckname[ukeysize - 1] == '\0' && uchecksize > ukeysize)
			{
				return 1;
			}
		}
	}
	else if (!strncmp (keyname, checkname, keysize - 1))
	{
		if ((ucheckname[ukeysize - 1] == '\0') && (uchecksize > ukeysize)) return 1;
	}
	return 0;
}