static int elektraResolveSystemBuildin (ElektraResolved * handle, ElektraResolveTempfile tmpDir, Key * warningsKey) { size_t filenameSize = sizeof (KDB_DB_SYSTEM) + elektraStrLen (handle->relPath) + sizeof ("/"); char * resolved = NULL; if (KDB_DB_SYSTEM[0] == '~') { char * resolvedPath = elektraMalloc (filenameSize); strcpy (resolvedPath, KDB_DB_SYSTEM); strcat (resolvedPath, "/"); strcat (resolvedPath, handle->relPath); char * oldPath = handle->relPath; handle->relPath = resolvedPath; elektraResolveSystemPasswd (handle, warningsKey); elektraFree (resolvedPath); handle->relPath = oldPath; } else { resolved = elektraMalloc (filenameSize); strcpy (resolved, KDB_DB_SYSTEM); strcat (resolved, "/"); strcat (resolved, handle->relPath); handle->fullPath = resolved; } elektraResolveFinishByFilename (handle, tmpDir); return 1; }
static int elektraResolveSystemBuildin (resolverHandle * p, Key * warningsKey) { size_t filenameSize = sizeof (KDB_DB_SYSTEM) + strlen (p->path) + sizeof ("/") + 1; if (KDB_DB_SYSTEM[0] == '~') { const char * oldPath = p->path; char * path = elektraMalloc (filenameSize); strcpy (path, KDB_DB_SYSTEM); strcat (path, "/"); strcat (path, p->path); p->path = path; elektraResolvePasswdHome (p, warningsKey); elektraFree (path); p->path = oldPath; } else { p->filename = elektraMalloc (filenameSize); strcpy (p->filename, KDB_DB_SYSTEM); strcat (p->filename, "/"); strcat (p->filename, p->path); } elektraResolveFinishByFilename (p); return 1; }
static void elektraResolveSystem (resolverHandle * p, Key * errorKey) { char * system = getenv ("ALLUSERSPROFILE"); if (!system) { system = ""; ELEKTRA_ADD_WARNING (90, errorKey, "could not get ALLUSERSPROFILE, using /"); } else { escapePath (system); } if (p->path[0] == '/') { /* Use absolute path */ size_t filenameSize = strlen (system) + strlen (p->path) + 1; p->filename = elektraMalloc (filenameSize); strcpy (p->filename, system); strcat (p->filename, p->path); return; } size_t filenameSize = sizeof (KDB_DB_SYSTEM) + strlen (system) + strlen (p->path) + sizeof ("/") + 1; p->filename = elektraMalloc (filenameSize); strcpy (p->filename, system); strcat (p->filename, KDB_DB_SYSTEM); strcat (p->filename, "/"); strcat (p->filename, p->path); return; }
static int elektraResolvePasswdHome (resolverHandle * p, Key * warningsKey) { ssize_t bufSize = sysconf (_SC_GETPW_R_SIZE_MAX); if (bufSize == -1) bufSize = 16384; // man 3 getpwuid char * buf = elektraMalloc (bufSize); if (!buf) return -1; struct passwd pwd; struct passwd * result; int s; s = getpwuid_r (getuid (), &pwd, buf, bufSize, &result); if (result == NULL) { elektraFree (buf); if (s != 0) { ELEKTRA_ADD_WARNING (90, warningsKey, strerror (s)); } return -1; } const char * home = pwd.pw_dir; size_t filenameSize = elektraStrLen (home) + elektraStrLen (p->path) - 1; p->filename = elektraMalloc (filenameSize); snprintf (p->filename, filenameSize, "%s/%s", home, (p->path) + 2); elektraFree (buf); return 0; }
static char * loadFile (FILE * fh) { /* open the file */ char * content = 0; if (fseek (fh, 0, SEEK_END) != 0) return 0; long fileSize = ftell (fh); rewind (fh); if (fileSize > 0) { content = elektraMalloc (fileSize * sizeof (char) + 1); if (content == 0) return 0; int readBytes = fread (content, sizeof (char), fileSize, fh); if (feof (fh) || ferror (fh) || readBytes != fileSize) return 0; /* null terminate the string, as fread doesn't do it */ content[fileSize] = 0; } else if (fileSize == 0) { content = elektraMalloc (1); if (content == 0) return 0; *content = (char)0; } return content; }
static void test_keyGetBinary (const size_t storagePlugin, const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; KeySet * ks = metaTestKeySet (); const char * name = "user/tests/storage/specialkey"; size_t realValueSize = 42; void * value = elektraMalloc (realValueSize); memset (value, 42, realValueSize); Key * key = keyNew (name, KEY_END); keySetBinary (key, value, realValueSize); ksAppendKey (ks, key); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); Key * found = ksLookupByName (ks, name, 0); succeed_if (found, "did not find key"); ssize_t apiValueSize = keyGetValueSize (found); char * apiValue = elektraMalloc (apiValueSize); succeed_if (keyGetBinary (found, apiValue, apiValueSize) == (ssize_t) realValueSize, "Key binary has wrong size"); succeed_if (elektraStrNCmp (value, apiValue, realValueSize) == 0, "Key binary value is wrong"); elektraFree (apiValue); elektraFree (value); keyDel (parentKey); ksDel (ks); closeStoragePlugin (storagePlugin); }
/** * Converts string to (@p direction = @c UTF8_TO) and from * (@p direction = @c UTF8_FROM) UTF-8. * * Since Elektra provides portability for key names and string values between * different codesets, you should use this helper in your backend to convert * to and from universal UTF-8 strings, when storing key names, values and * comments. * * Broken locales in applications can cause problems too. Make sure to load * the environment locales in your application using * @code setlocale (LC_ALL, ""); * @endcode * * Otherwise kdbbUTF8Engine and this plugin will quit * with error when non-ascii characters appear. * * Binary values are not effected. * * If iconv() or nl_langinfo() is not available on your system, or if iconv() * this plugin can't be used. * * @param direction must be @c UTF8_TO (convert from current non-UTF-8 to * UTF-8) or @c UTF8_FROM (convert from UTF-8 to current non-UTF-8) * @param string before the call: the string to be converted; after the call: * reallocated to carry the converted string * @param inputOutputByteSize before the call: the size of the string including * leading NULL; after the call: the size of the converted string including * leading NULL * @retval 0 on success * @retval -1 on failure * @ingroup backendhelper * */ int kdbbUTF8Engine (Plugin * handle, int direction, char ** string, size_t * inputOutputByteSize) { /* Current solution is not very complete. * Iconv might well be available when a usable nl_langinfo is not. * In this case we it should be possible to determine charset through other means * See http://www.cl.cam.ac.uk/~mgk25/unicode.html#activate for more info on a possible solution */ char * converted = 0; char *readCursor, *writeCursor; size_t bufferSize; iconv_t converter; if (!*inputOutputByteSize) return 0; if (!kdbbNeedsUTF8Conversion (handle)) return 0; if (direction == UTF8_TO) converter = iconv_open (getTo (handle), getFrom (handle)); else converter = iconv_open (getFrom (handle), getTo (handle)); if (converter == (iconv_t) (-1)) return -1; /* work with worst case, when all chars are wide */ bufferSize = *inputOutputByteSize * 4; converted = elektraMalloc (bufferSize); if (!converted) return -1; readCursor = *string; writeCursor = converted; /* On some systems and with libiconv, arg1 is const char **. * ICONV_CONST is defined by configure if the system needs this */ if (iconv (converter, &readCursor, inputOutputByteSize, &writeCursor, &bufferSize) == (size_t) (-1)) { elektraFree (converted); iconv_close (converter); return -1; } /* calculate the UTF-8 string byte size, that will be returned */ *inputOutputByteSize = writeCursor - converted; /* store the current kdbbDecoded string for future free */ readCursor = *string; /* allocate an optimal size area to store the converted string */ *string = elektraMalloc (*inputOutputByteSize); /* copy all that matters for returning */ memcpy (*string, converted, *inputOutputByteSize); /* release memory used by passed string */ elektraFree (readCursor); /* release buffer memory */ elektraFree (converted); /* release the conversor engine */ iconv_close (converter); return 0; }
int elektraIconvSet (Plugin * handle, KeySet * returned, Key * parentKey) { Key * cur; if (!kdbbNeedsUTF8Conversion (handle)) return 0; ksRewind (returned); while ((cur = ksNext (returned)) != 0) { if (keyIsString (cur)) { /* String or similar type of value */ size_t convertedDataSize = keyGetValueSize (cur); char * convertedData = elektraMalloc (convertedDataSize); memcpy (convertedData, keyString (cur), keyGetValueSize (cur)); if (kdbbUTF8Engine (handle, UTF8_TO, &convertedData, &convertedDataSize)) { ELEKTRA_SET_ERRORF (46, parentKey, "Could not convert string %s, got result %s," " encoding settings are from %s to %s (but swapped for write)", keyString (cur), convertedData, getFrom (handle), getTo (handle)); elektraFree (convertedData); return -1; } keySetString (cur, convertedData); elektraFree (convertedData); } const Key * meta = keyGetMeta (cur, "comment"); if (meta) { /* String or similar type of value */ size_t convertedDataSize = keyGetValueSize (meta); char * convertedData = elektraMalloc (convertedDataSize); memcpy (convertedData, keyString (meta), keyGetValueSize (meta)); if (kdbbUTF8Engine (handle, UTF8_TO, &convertedData, &convertedDataSize)) { ELEKTRA_SET_ERRORF (46, parentKey, "Could not convert string %s, got result %s," " encodings settings are from %s to %s (but swapped for write)", keyString (meta), convertedData, getFrom (handle), getTo (handle)); elektraFree (convertedData); return -1; } keySetMeta (cur, "comment", convertedData); elektraFree (convertedData); } } return 1; /* success */ }
/** * @brief Given filename, calcualtes dirname+tempfile * * @param p resolverHandle with filename set */ static void elektraResolveFinishByFilename(resolverHandle *p) { size_t filenameSize = strlen(p->filename); p->dirname = elektraMalloc (filenameSize); char * dup = strdup(p->filename); //dirname might change the buffer, so better work on a copy strcpy (p->dirname, dirname(dup)); elektraFree (dup); p->tempfile = elektraMalloc (filenameSize + POSTFIX_SIZE); elektraGenTempFilename(p->tempfile, p->filename); }
static Key * prefToKey (Key * parentKey, PrefType type, const char * pref) { Key * key = keyNew (keyName (parentKey), KEY_END); keyAddBaseName (key, prefix[type]); char * localString = elektraStrDup (pref); char * cPtr = strstr (localString, ","); *cPtr = '\0'; char * sPtr = localString; ++sPtr; *sPtr++ = '\0'; char * ePtr = cPtr - 1; elektraRstrip (sPtr, &ePtr); size_t keyLen = ePtr - sPtr; char * prefKey = elektraMalloc (keyLen + 1); snprintf (prefKey, keyLen + 1, "%s", sPtr); char * tPtr = strtok (prefKey, "."); if (tPtr) keyAddBaseName (key, tPtr); while ((tPtr = strtok (NULL, ".")) != NULL) { keyAddBaseName (key, tPtr); } elektraFree (prefKey); sPtr = cPtr + 1; sPtr = elektraLskip (sPtr); ePtr = strrchr (sPtr, ')'); *ePtr-- = '\0'; elektraRstrip (sPtr, &ePtr); size_t argLen = ePtr - sPtr + 1; char * prefArg = elektraMalloc (argLen + 1); snprintf (prefArg, argLen + 1, "%s", sPtr); if (!strcmp (prefArg, "true") || !(strcmp (prefArg, "false"))) { keySetMeta (key, "type", "boolean"); keySetString (key, prefArg); } else if (prefArg[0] == '"' && prefArg[strlen (prefArg) - 1] == '"') { // TODO: else if list keySetMeta (key, "type", "string"); *prefArg = '\0'; *(prefArg + (strlen (prefArg + 1))) = '\0'; keySetString (key, (prefArg + 1)); } else { keySetMeta (key, "type", "integer"); keySetString (key, prefArg); } elektraFree (prefArg); elektraFree (localString); return key; }
/** * Generate a C-Style key and stream it. * * This keyset can be used to include as c-code for * applikations using elektra. * * @param key the key object to work with * @param stream the file pointer where to send the stream * @param options KDB_O_SHOWINDICES, KDB_O_IGNORE_COMMENT, KDB_O_SHOWINFO * @retval 1 on success * @ingroup stream */ int keyGenerate(const Key * key, FILE *stream, option_t options) { size_t s; char * str; size_t c; char * com; size_t n; char * nam; n = keyGetNameSize (key); if (n>1) { nam = (char*) elektraMalloc (n); if (nam == NULL) return -1; keyGetName (key, nam, n); fprintf(stream,"\tkeyNew (\"%s\"", nam); elektraFree (nam); } s = keyGetValueSize (key); if (s>1) { str = (char*) elektraMalloc (s); if (str == NULL) return -1; if (keyIsBinary(key)) keyGetBinary(key, str, s); else keyGetString (key, str, s); fprintf(stream,", KEY_VALUE, \"%s\"", str); elektraFree (str); } c = keyGetCommentSize (key); if (c>1) { com = (char*) elektraMalloc (c); if (com == NULL) return -1; keyGetComment (key, com, c); fprintf(stream,", KEY_COMMENT, \"%s\"", com); elektraFree (com); } if (! (keyGetMode(key) == 0664 || (keyGetMode(key) == 0775))) { fprintf(stream,", KEY_MODE, 0%3o", keyGetMode(key)); } fprintf(stream,", KEY_END)"); if (options == 0) return 1; /* dummy to make icc happy */ return 1; }
/** * @retval 0 if variant did not have a result * @retval 1 on success */ static int elektraResolveSystem (char variant, resolverHandle * p, Key * warningsKey) { // hardcoded path wins against variants for now if (p->path[0] == '/') { /* Use absolute path */ size_t filenameSize = strlen (p->path) + 1; p->filename = elektraMalloc (filenameSize); strcpy (p->filename, p->path); elektraResolveFinishByFilename (p); return 1; } if (p->path[0] == '~') { if (elektraResolvePasswdHome (p, warningsKey) == -1) return -1; elektraResolveFinishByFilename (p); return 1; } switch (variant) { case 'x': return elektraResolveSystemXDG (p, warningsKey); case 'b': return elektraResolveSystemBuildin (p, warningsKey); // TODO: also document in doc/COMPILE.md } return -1; }
static void elektraResolveUser (resolverHandle * p, Key * warningsKey) { p->filename = elektraMalloc (KDB_MAX_PATH_LENGTH); #if defined(_WIN32) CHAR home[MAX_PATH]; if (SUCCEEDED (SHGetFolderPath (NULL, CSIDL_PROFILE, NULL, 0, home))) { escapePath (home); } else { strcpy (home, ""); ELEKTRA_ADD_WARNING (90, warningsKey, "could not get home (CSIDL_PROFILE), using /"); } #else char * home = (char *)getenv ("HOME"); if (!home) { home = ""; ELEKTRA_ADD_WARNING (90, warningsKey, "could not get home, using /"); } #endif strcpy (p->filename, home); strcat (p->filename, "/"); strncat (p->filename, p->path, KDB_MAX_PATH_LENGTH); }
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; }
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; }
static void test_elektraMalloc (void) { char * buffer = 0; buffer = elektraMalloc (50); exit_if_fail (buffer, "buffer must not be 0 after allocation"); elektraRealloc ((void **)&buffer, 100); exit_if_fail (buffer, "buffer must not be 0 after reallocation"); elektraRealloc ((void **)&buffer, 20); exit_if_fail (buffer, "buffer must not be 0 after reallocation"); elektraFree (buffer); buffer = elektraCalloc (50); exit_if_fail (buffer, "buffer must not be 0 after allocation"); for (int i = 0; i < 50; ++i) { succeed_if (buffer[i] == 0, "elektraCalloc did not initialize buffer with zeros"); } elektraRealloc ((void **)&buffer, 100); exit_if_fail (buffer, "buffer must not be 0 after reallocation"); elektraRealloc ((void **)&buffer, 20); exit_if_fail (buffer, "buffer must not be 0 after reallocation"); char * dup = elektraStrNDup (buffer, 20); exit_if_fail (dup, "could not duplicate buffer"); elektraFree (buffer); buffer = 0; for (int i = 0; i < 20; ++i) { succeed_if (dup[i] == 0, "elektraStrNDup did not correctly copy zero-buffer"); } elektraFree (dup); }
/** * Check if supplied filename is ok. * * This symbol is exported and used during mounting. * * @retval 1 on success (Relative path) * @retval 0 on success (Absolute path) * @retval -1 on a non-valid file */ int ELEKTRA_PLUGIN_FUNCTION(resolver,checkFile)(const char* filename) { if (!filename) return -1; if (filename[0] == '0') return -1; size_t size = strlen(filename); char *buffer = elektraMalloc(size + sizeof ("system/")); strcpy(buffer, "system/"); strcat(buffer, filename); /* Because of the outbreak bugs these tests are not enough */ Key *check = keyNew(buffer, KEY_END); if (!strcmp(keyName(check), "")) goto error; if (!strcmp(keyName(check), "system")) goto error; keyDel(check); elektraFree (buffer); /* Be strict, don't allow any .., even if it would be ok sometimes */ if (strstr (filename, "..") != 0) return -1; if (filename[0] == '/') return 0; return 1; error: keyDel (check); elektraFree (buffer); return -1; }
int elektraSpecloadOpen (Plugin * handle, Key * errorKey) { Specload * specload = elektraMalloc (sizeof (Specload)); KeySet * conf = elektraPluginGetConfig (handle); if (ksLookupByName (conf, "system/module", 0) != NULL || ksLookupByName (conf, "system/sendspec", 0) != NULL) { elektraFree (specload); return ELEKTRA_PLUGIN_STATUS_SUCCESS; } if (!getAppAndArgs (conf, &specload->app, &specload->argv, errorKey)) { elektraFree (specload); return ELEKTRA_PLUGIN_STATUS_ERROR; } specload->quickDumpConfig = ksNew (0, KS_END); specload->quickDump = elektraInvokeOpen ("quickdump", specload->quickDumpConfig, errorKey); if (!specload->quickDump) { elektraFree (specload); return ELEKTRA_PLUGIN_STATUS_ERROR; } elektraPluginSetData (handle, specload); return ELEKTRA_PLUGIN_STATUS_SUCCESS; }
static void setSubOrderNumber(Key *key, const char *oldOrder) { char *lastIndexPtr = NULL; char *newOrder = elektraMalloc(elektraStrLen(oldOrder)+ELEKTRA_MAX_ARRAY_SIZE); if ((lastIndexPtr = strrchr(oldOrder, '/'))) { kdb_long_long_t subIndex = 0; char *ptr = lastIndexPtr; ++ptr; //skip / ++ptr; //skip # while (*ptr == '_') { ++ptr; } elektraReadArrayNumber(ptr, &subIndex); ++subIndex; int len = (lastIndexPtr+1) - oldOrder; char buffer[ELEKTRA_MAX_ARRAY_SIZE]; elektraWriteArrayNumber(buffer, subIndex); sprintf(newOrder, "%.*s%s", len, oldOrder, buffer); } else { sprintf(newOrder, "%s/#1", oldOrder); } keySetMeta(key, "order", newOrder); elektraFree(newOrder); }
static int iniCommentToMeta (void *vhandle, const char *comment) { CallbackHandle *handle = (CallbackHandle *)vhandle; size_t commentSize = strlen (comment) + 1; if (!handle->collectedComment) { handle->collectedComment = elektraMalloc (commentSize); if (!handle->collectedComment) return 0; strncpy (handle->collectedComment, comment, commentSize); } else { size_t newCommentSize = strlen (handle->collectedComment) + commentSize + 2; handle->collectedComment = realloc (handle->collectedComment, newCommentSize); if (!handle->collectedComment) return 0; strcat (handle->collectedComment, "\n"); strncat (handle->collectedComment, comment, newCommentSize); } return 1; }
static int elektraResolveEnvUser(resolverHandle *p) { const char* owner = getenv("USER"); if (!owner || !strcmp(owner, "")) { return 0; } Key *canonify = keyNew("user", KEY_END); keyAddName(canonify, owner); size_t dirnameSize = sizeof(KDB_DB_HOME "/") + keyGetNameSize(canonify) + sizeof("/" KDB_DB_USER); p->dirname= elektraMalloc (dirnameSize); strcpy (p->dirname, KDB_DB_HOME "/"); strcat (p->dirname, keyName(canonify) +5); // cut user/ if (p->path[0] != '/') { strcat (p->dirname, "/" KDB_DB_USER); } keyDel(canonify); return 1; }
static void elektraDropCurrentKey (KeySet * ks, Key * warningKey, const Backend * curHandle, const char * msg) { const Key * k = ksCurrent (ks); const size_t sizeOfStaticText = 100; char * warningMsg = elektraMalloc (keyGetNameSize (curHandle->mountpoint) + keyGetValueSize (curHandle->mountpoint) + keyGetNameSize (k) + strlen (msg) + sizeOfStaticText); strcpy (warningMsg, "drop key "); const char * name = keyName (k); if (name) { strcat (warningMsg, name); } else { strcat (warningMsg, "(no name)"); } strcat (warningMsg, " not belonging to "); strcat (warningMsg, keyName (curHandle->mountpoint)); strcat (warningMsg, " with name "); strcat (warningMsg, keyString (curHandle->mountpoint)); strcat (warningMsg, " because "); strcat (warningMsg, msg); ELEKTRA_ADD_WARNING (79, warningKey, warningMsg); elektraFree (warningMsg); cursor_t c = ksGetCursor (ks); keyDel (elektraKsPopAtCursor (ks, c)); ksSetCursor (ks, c); elektraKsPrev (ks); // next ksNext() will point correctly again }
/** * Creates a new KeyRegistration structure and appends it at the end of the registration list * @internal * * @param pluginState internal plugin data structure * @param key key * @param callback callback for changes * @param context context for callback * @param freeContext context needs to be freed on close * * @return pointer to created KeyRegistration structure or NULL if memory allocation failed */ static KeyRegistration * elektraInternalnotificationAddNewRegistration (PluginState * pluginState, Key * key, ElektraNotificationChangeCallback callback, void * context, int freeContext) { KeyRegistration * item = elektraMalloc (sizeof *item); if (item == NULL) { return NULL; } item->next = NULL; item->lastValue = NULL; item->name = elektraStrDup (keyName (key)); item->callback = callback; item->context = context; item->sameOrBelow = 0; item->freeContext = freeContext; if (pluginState->head == NULL) { // Initialize list pluginState->head = pluginState->last = item; } else { // Make new item end of list pluginState->last->next = item; pluginState->last = item; } return item; }
static KeySet * getGlobKeys (Key * parentKey, KeySet * keys, enum GlobDirection direction) { KeySet * glob = ksNew (0, KS_END); Key * k = 0; size_t parentsize = keyGetNameSize (parentKey); Key * userGlobConfig = 0; Key * systemGlobConfig = 0; Key * userDirGlobConfig = 0; Key * systemDirGlobConfig = 0; userGlobConfig = keyNew ("user/glob", KEY_END); systemGlobConfig = keyNew ("system/glob", KEY_END); switch (direction) { case GET: userDirGlobConfig = keyNew ("user/glob/get", KEY_END); systemDirGlobConfig = keyNew ("system/glob/get", KEY_END); break; case SET: userDirGlobConfig = keyNew ("user/glob/set", KEY_END); systemDirGlobConfig = keyNew ("system/glob/set", KEY_END); break; } while ((k = ksNext (keys)) != 0) { /* use only glob keys for the current direction */ if (keyIsDirectBelow (userGlobConfig, k) || keyIsDirectBelow (systemGlobConfig, k) || keyIsDirectBelow (userDirGlobConfig, k) || keyIsDirectBelow (systemDirGlobConfig, k)) { keySetMeta (k, "glob/flags", getGlobFlags (keys, k)); /* Look if we have a string */ size_t valsize = keyGetValueSize (k); if (valsize < 2) continue; /* We now know we want that key. Dup it to not change the configuration. */ Key * ins = keyDup (k); /* Now look if we want cascading for the key */ if (keyString (k)[0] == '/') { char * newstring = elektraMalloc (valsize + parentsize); strcpy (newstring, keyName (parentKey)); strcat (newstring, keyString (k)); keySetString (ins, newstring); elektraFree (newstring); } ksAppendKey (glob, ins); } } keyDel (userGlobConfig); keyDel (systemGlobConfig); keyDel (userDirGlobConfig); keyDel (systemDirGlobConfig); return glob; }
static void validateArrayRange (Key * parent, long validCount, Key * specKey) { const Key * arrayRange = keyGetMeta (specKey, "array"); if (arrayRange != NULL) { char * rangeString = elektraMalloc (keyGetValueSize (arrayRange)); keyGetString (arrayRange, rangeString, keyGetValueSize (arrayRange)); char * delimPtr = strchr (rangeString, '-'); long min = 0; long max = 0; if (delimPtr) { char * maxString = delimPtr + 1; *delimPtr = '\0'; char * minString = rangeString; min = atoi (minString); max = atoi (maxString); } else { min = max = atoi (rangeString); } if (validCount < min || validCount > max) { char buffer[MAX_CHARS_IN_LONG + 1]; snprintf (buffer, sizeof (buffer), "%ld", validCount); keySetMeta (parent, "conflict/range", buffer); } elektraFree (rangeString); } }
static void test_keyGetBaseName (const size_t storagePlugin, const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; KeySet * ks = metaTestKeySet (); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); const char * name = "user/tests/storage/a"; Key * found = ksLookupByName (ks, name, 0); succeed_if (found, "did not find key"); const char * constBaseName = "a"; size_t constBaseNameSize = elektraStrLen (constBaseName); ssize_t baseNameSize = keyGetFullNameSize (found); char * baseName = elektraMalloc (baseNameSize); ssize_t ret = keyGetBaseName (found, baseName, baseNameSize); if (ret < 1) { yield_error ("Key base name NULL or size error"); } else { succeed_if ((size_t) ret == elektraStrLen (constBaseName), "Key base name has wrong size"); } succeed_if (elektraStrNCmp (constBaseName, baseName, constBaseNameSize) == 0, "Key base name is wrong"); elektraFree (baseName); keyDel (parentKey); ksDel (ks); closeStoragePlugin (storagePlugin); }
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; }
static void test_keyValue (const size_t storagePlugin, const char * tmpFile) { Key * parentKey = keyNew (TEST_ROOT_KEY, KEY_VALUE, tmpFile, KEY_END); open_storage_plugin (storagePlugin); Plugin * plugin = plugins[storagePlugin]; KeySet * ks = metaTestKeySet (); const char * name = "user/tests/storage/specialkey"; size_t valueSize = 42; void * value = elektraMalloc (valueSize); memset (value, 42, valueSize); Key * key = keyNew (name, KEY_END); keySetBinary (key, value, valueSize); ksAppendKey (ks, keyDup (key)); succeed_if (plugin->kdbSet (plugin, ks, parentKey) == 1, "kdbSet was not successful"); succeed_if (plugin->kdbGet (plugin, ks, parentKey) == 1, "kdbGet was not successful"); Key * found = ksLookupByName (ks, name, 0); succeed_if (found, "did not find key"); compare_key (key, found); elektraFree (value); keyDel (parentKey); ksDel (ks); keyDel (key); closeStoragePlugin (storagePlugin); }
// elektra wildcard syntax to fnmatch syntax static char * keyNameToMatchingString (const Key * key) { uint8_t arrayCount = 0; char * name = strchr (keyName (key), '/'); if (!name) return elektraStrDup (keyName (key)); for (char * ptr = name; *ptr != '\0'; ++ptr) if (*ptr == '#') ++arrayCount; char * pattern = elektraMalloc (elektraStrLen (name) + arrayCount); char * dst = pattern; for (char * src = (name + 1); *src != '\0'; ++src) { if (*src == '_' && *(src - 1) == '/' && (*(src + 1) == '/' || *(src + 1) == '\0')) { *dst++ = '*'; } else if (*src == '#' && *(src - 1) == '/' && (*(src + 1) == '/' || *(src + 1) == '\0')) { *dst++ = '#'; *dst++ = '*'; } else { *dst++ = *src; } } *dst = '\0'; return pattern; }
/** * @internal * * Set raw data as the value of a key. * If NULL pointers are passed, key value is cleaned. * This method will not change or set the key type, and should only * be used internally in elektra. * * @param key the key object to work with * @param newBinary array of bytes to set as the value * @param dataSize number bytes to use from newBinary, including the final NULL * @return The number of bytes actually set in internal buffer. * @retval 1 if it was a string which was deleted * @retval 0 if it was a binary which was deleted * @see keySetType(), keySetString(), keySetBinary() * @ingroup keyvalue */ ssize_t keySetRaw(Key *key, const void *newBinary, size_t dataSize) { if (!key) return -1; if (key->flags & KEY_FLAG_RO_VALUE) return -1; if (!dataSize || !newBinary) { if (key->data.v) { elektraFree (key->data.v); key->data.v=0; } key->dataSize = 0; set_bit(key->flags, KEY_FLAG_SYNC); if (keyIsBinary(key)) return 0; return 1; } key->dataSize=dataSize; if (key->data.v) { char *p=0; p=realloc(key->data.v,key->dataSize); if (0==p) return -1; key->data.v=p; } else { char *p=elektraMalloc(key->dataSize); if (0==p) return -1; key->data.v=p; } memcpy(key->data.v,newBinary,key->dataSize); set_bit(key->flags, KEY_FLAG_SYNC); return keyGetValueSize (key); }