1 /***************************************************************************
2 ini.c - Backend for ini-style like files
6 copyright : (C) 2005 by Markus Raab
7 email : debian@markus-raab.org
8 ***************************************************************************/
10 /***************************************************************************
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the BSD License (revised). *
15 ***************************************************************************/
21 int kdbOpen_ini(KDB *handle)
23 KDBCap *cap = kdbhGetCapability (handle);
56 kdbhSetBackendData (handle, malloc (sizeof (backendData)));
58 /* backend initialization logic */
63 int kdbClose_ini(KDB *handle)
65 free (kdbhGetBackendData (handle));
67 /* free all backend resources and shut it down */
69 return 0; /* success */
72 ssize_t kdbGet_ini(KDB *handle, KeySet *returned, const Key *parentKey)
75 char t [MAX_PATH_LENGTH];
76 Key * write = keyDup (parentKey);
80 fprintf (stderr, "file_name: %s\n", t);
82 fprintf (stderr, "base_name: %s\n", t);
85 /**Immediately call IniChooseFile (will work recursively)*/
86 rc = IniChooseFile (handle, write, returned, 0);
92 ssize_t kdbSet_ini(KDB *handle, KeySet *ks, const Key *parentKey)
94 return IniSetKeys (handle, ks);
99 * Returns a filename from the Key which can be opened for forKey
101 * The name returned should be correct, because
102 * it removes subdirs and the keyname.
104 * It even tests with kdbStatKey if the File exists.
105 * So be prepaired that stat information is filled
108 * @see IniSearchFileName
109 * @param filename must be allocated MAX_PATH_LENGTH space.
110 * Previous Content of Filename will be destroyed afterwards.
114 size_t IniSearchFileName (KDB *handle, Key * forKey, char * filename)
120 length = file_name (forKey, filename);
124 fprintf (stderr, "Search %s\n", filename);
126 end = strrchr (filename, '/');
129 fprintf (stderr, "Could not find any file\n");
134 stat_file (forKey, filename);
135 info = keyGetType (forKey);
136 } while (!(info & KEY_TYPE_FILE));
143 * Get out all the keys of a file
145 * @param keyFileName: Name of the file
146 * @param keyRoot: Name of the root of files
147 * The root will be added before the keyName
151 ssize_t IniGetKeys (KDB *handle, char * keyFileName, char * keyRoot, KeySet * returned)
156 if (open_file (handle, keyFileName, O_RDONLY) == -1)
159 fprintf (stderr, "Could not open file %s\n", keyFileName);
161 /*errno = KDB_ERR_NOTFOUND;*/
168 fprintf (stderr, "Call read_key(%s)\n", keyRoot);
170 while ((pos=read_key (handle, key, keyRoot)) == 0)
173 fprintf (stderr, "Append key\n");
175 ksAppendKey(returned,key);
180 keyDel (key); /* delete the not used key left*/
184 return 0; /* success */
188 * Reads the contents of the whole file which Key
191 * The Keys will be added in the Keyset.
195 int IniReadFile (KDB *handle, Key * key, KeySet * returned, unsigned long options)
197 char filename [MAX_PATH_LENGTH];
202 fprintf (stderr, "IniReadfile\n");
205 file_name(key, filename);
207 keyLength = keyGetNameSize (key);
208 keyname = malloc (keyLength);
209 keyGetName (key, keyname, keyGetNameSize (key));
212 fprintf (stderr, "Call IniGetKeys(filename: %s, keyRoot: %s,returned)\n",
215 IniGetKeys (handle, filename, keyname, returned);
217 if (keyLength >0) free (keyname);
223 * This mapper chooses between the different
224 * styles of files to start the correct function.
226 * For files it starts IniReadFile
227 * For directorys it starts IniReadDir
231 int IniChooseFile(KDB *handle, Key * key, KeySet * returned, unsigned long options)
233 char filename [MAX_PATH_LENGTH];
237 file_name(key, filename);
238 stat_file (key, filename);
241 fprintf (stderr, "IniChooseFile, pathName: %s\n", filename);
244 if (keyGetType (key) == KEY_TYPE_DIR)
246 if (filename[strlen(filename)-1] != '/')
248 keylength = keyGetNameSize(key);
249 keyname = malloc (keylength + 2);
250 keyGetName (key, keyname, keylength);
251 keyname[keylength-1] = '/';
252 keyname[keylength] = '\0';
253 keySetName (key, keyname);
257 return IniReadDir (handle, key, returned, options);
260 if (keyGetType (key) == KEY_TYPE_FILE)
262 return IniReadFile (handle, key, returned, options);
266 fprintf (stderr, "Not a directory or file!");
273 * Reads all Keys of a directory.
275 * For every key the mapper IniChooseFile
280 int IniReadDir(KDB *handle, Key * key, KeySet * returned, unsigned long options)
282 char pathName [MAX_PATH_LENGTH];
283 char keyname [MAX_PATH_LENGTH];
284 char keypath [MAX_PATH_LENGTH];
285 char filename [MAX_PATH_LENGTH];
290 fprintf (stderr, "IniReadDir\n");
292 file_name (key, pathName);
293 dir = open_dir (pathName);
295 fprintf (stderr, "Could not open directory %s\n", pathName);
299 keyGetName (key, keypath, MAX_PATH_LENGTH);
301 while (read_dir (dir,filename) == 0)
303 if ( strcmp(filename, ".") == 0 ||
304 strcmp(filename, "..") == 0)
307 if (filename[0] == '.' && !(options & KDB_O_INACTIVE))
311 fprintf (stderr, "Next entry filename: %s\n", filename);
313 strncpy(keyname, keypath, MAX_PATH_LENGTH);
314 strcat(keyname, filename);
315 keySetName (key, keyname);
318 fprintf (stderr, "New keyname: %s\n", keyname);
320 ret = IniChooseFile (handle, key, returned, options);
325 fprintf (stderr, "Could not close directory\n");
334 /**Walks through a file and lookups if the first key of a keyset is in the
335 * given Keyset. When found it overwrites the key. It also checks if any
336 * of the other keys can be written in that file under that context. If
337 * not, the keys will remain in the Keyset.
339 * So, the KeySet will be empty after complete successful writing. At
340 * least one key is guranteed to be written when it was successful.
342 * The whole idea behind that concept is, that open/close and searching
343 * within a file is complete minimized. The disadvantage is, that a
344 * fast ksLookupKey is required, because every readed key will be compared
345 * with all keys in keyset (its not implemented in elektra right now,
346 * so it will consume linear more time, but only in memory, not on
349 * When not found it writes out the keys before the sectionend.
352 * setting keys new keys will introduce new folders and files
355 * At least one key will be written!
357 * @return >=0 on success
358 * @return -1 on failure (Keyset may be changed then!)
359 * @return #nr when #nr keys could not written to file
362 int IniSetKeys (KDB *handle, KeySet * origKeys)
364 char keyFileName [MAX_PATH_LENGTH];
368 char * keyFullName = NULL;
369 char * keyRoot = NULL;
372 Key * origKey; /*First key which will introduce opening file*/
373 Key * setKey; /*Used for getting the keys which may be set*/
374 Key * key = keyNew(0);
379 fprintf (stderr, "IniSetKeys() entered\n");
383 origKey = ksNext (origKeys); /* Open file for this key*/
384 key = keyDup (origKey); /* for searching*/
386 pos = IniSearchFileName(handle, key, keyFileName);
389 fprintf (stderr, "after SearchFileName ...\n");
392 if (pos == -1) /* no such file exists*/
394 file_name(key,keyFileName);
395 create_dir(keyFileName);
398 keySize = keyGetNameSize (key);
399 keyFullName = malloc (keySize+1);
400 if (keyFullName == NULL) goto memerror;
401 keyGetName(key, keyFullName, keySize);
403 end = strrchr (keyFullName, '/'); /* dirname*/
405 keyRoot = malloc (strlen (keyFullName));
406 if (keyRoot == NULL) goto memerror;
407 strcpy (keyRoot, keyFullName);
408 if (end) *end = '/'; /*revert keyname*/
411 fprintf (stderr, "keyRoot: %s, keyName: %s\n", keyRoot, keyFullName);
412 fprintf (stderr, "Set Key [%d] in File: %s\n",keySize, keyFileName);
415 if (open_file (handle, keyFileName, O_RDWR) == -1)
418 fprintf (stderr, "Could not open file %s\n", keyFileName);
420 ksAppendKey(origKeys, origKey);
421 /*errno = KDB_ERR_NOTFOUND;*/
425 while ((pos=read_key (handle, key, keyRoot)) == 0)
427 if ((setKey = ksLookupByName (origKeys, key->key, 0)) != NULL)
428 { /* right Key found*/
430 fprintf (stderr, "Key found\n");
431 fprintf(stderr, "Name: (%s), Value: (%s), Comment: (%s)\n",
432 keyName (setKey), (char *) keyValue(setKey),
433 (char *) keyComment (setKey));
436 write_key(handle, setKey, oldpos);
438 if ((keyCompare (key, origKey) & KEY_NAME) == 0)
439 pos = 1; /*Start Key found, good!*/
441 oldpos = ftell (FILEPTR);
443 if (pos != 1) { /* key not found, add to the end*/
445 fprintf (stderr, "Key not found!\n");
447 fseek (FILEPTR, 0, SEEK_END);
448 oldpos = ftell(FILEPTR);
449 /*TODO: write key here if not found
450 * write_key(setKey, oldpos);*/
452 } else if (pos == 1) { /* key found, everything went ok!*/
464 fprintf (stderr, "leaving IniSetKeys()\n");
467 return pos; /* success */
470 /*errno=KDB_ERR_NOMEM;*/
473 fprintf (stderr, "Memory Error\n");
487 return kdbBackendExport(BACKENDNAME,
488 KDB_BE_OPEN, &kdbOpen_ini,
489 KDB_BE_CLOSE, &kdbClose_ini,
490 KDB_BE_GET, &kdbGet_ini,
491 KDB_BE_SET, &kdbSet_ini,
492 KDB_BE_VERSION, BACKENDVERSION,
493 KDB_BE_AUTHOR, "Markus Raab <elektra@libelektra.org>",
494 KDB_BE_LICENCE, "BSD",
495 KDB_BE_DESCRIPTION, "Key/Value Pairs are stored in files in following scheme: key1=value1;comment",