/** * 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; }
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; }
/** * @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; }
/** * Adds @p baseName (that will be escaped) to the current key name. * * A new baseName will be added, no other part of the key name will be * affected. * * Assumes that @p key is a directory and will append @p baseName to it. * The function adds the path separator for concatenating. * * So if @p key has name @c "system/dir1/dir2" and this method is called with * @p baseName @c "mykey", the resulting key will have the name * @c "system/dir1/dir2/mykey". * * When @p baseName is 0 nothing will happen and the size of the name is returned. * * The escaping rules apply as in @link keyname above @endlink. * * A simple example is: * @snippet basename.c add base basic * * E.g. if you add . it will be escaped: * @snippet testabi_key.c base1 add * * @see keySetBaseName() to set a base name * @see keySetName() to set a new name. * * @param key the key object to work with * @param baseName the string to append to the name * @return the size in bytes of the new key name including the ending NULL * @retval -1 if the key had no name * @retval -1 on NULL pointers * @retval -1 if key was inserted to a keyset before * @ingroup keyname * */ ssize_t keyAddBaseName (Key * key, const char * baseName) { if (!key) return -1; if (!baseName) return key->keySize; if (test_bit (key->flags, KEY_FLAG_RO_NAME)) return -1; if (!key->key) return -1; char * escaped = elektraMalloc (strlen (baseName) * 2 + 2); elektraEscapeKeyNamePart (baseName, escaped); size_t len = strlen (escaped); if (!strcmp (key->key, "/")) { key->keySize += len; } else { key->keySize += len + 1; } elektraRealloc ((void **)&key->key, key->keySize * 2); if (!key->key) { elektraFree (escaped); return -1; } if (strcmp (key->key, "/")) { key->key[key->keySize - len - 2] = KDB_PATH_SEPARATOR; } memcpy (key->key + key->keySize - len - 1, escaped, len); elektraFree (escaped); elektraFinalizeName (key); return key->keySize; }