1 // winregistry.cpp : Defines the entry point for the DLL application.
4 #include "winregistry.h"
7 int mapError(LONG err);
9 BOOL APIENTRY DllMain( HANDLE hModule,
10 DWORD ul_reason_for_call,
14 switch (ul_reason_for_call)
16 case DLL_PROCESS_ATTACH:
17 case DLL_THREAD_ATTACH:
18 case DLL_THREAD_DETACH:
19 case DLL_PROCESS_DETACH:
28 * @defgroup backend Elektra framework for pluggable backends
29 * @brief The tactics to create pluggable backends to libelektra.so
31 * Since version 0.4.9, Elektra can dynamically load different key storage
32 * backends. Fast jump to kdbBackendExport() to see an example of a backend
35 * The methods of class KDB that are backend dependent are kdbOpen(),
36 * kdbClose(), kdbGetKey(), kdbSetKey(), kdbStatKey(),
37 * kdbGetKeyChildKeys(), kdbRemove(), kdbRename(). So a backend must
38 * reimplement these methods.
40 * And methods that have a builtin default high-level inefficient
41 * implementation are kdbSetKeys(), kdbMonitorKey(), kdbMonitorKeys(). So
42 * it is suggested to reimplement them too, to make them more efficient.
44 * The other KDB methods are higher level. They use the above methods to
45 * do their job, and generally don't have to be reimplemented for a
48 * The backend must implement a method with name kdbBackendFactory() and no
49 * parameters, that is responsible of exporting the implementations of
50 * libelektra.so backend dependent methods.
52 * The backend implementation must:
54 #include <kdbbackend.h>
57 * <b>Better than that, a skeleton of a backend implementation is provided inside
58 * Elektra development package or source code tree, and should be used as a
59 * base for the implementation.</b>
61 * An elektrified program will use the backend defined by environment variable
62 * @e $KDB_BACKEND, The backend library is dynamically loaded when the program
63 * calls kdbOpen(), unless if the program is security/authentication/setuid
64 * related, in which it probably uses the more secure kdbOpenDefault() which
65 * completely ignores the @e $KDB_BACKEND environment and will use the
66 * @c "default" named backend defined by the sysadmin. Look at
67 * @c /lib/libelektra-default.so link to see the default backend for your
70 * Elektra source code or development package provides a skeleton and Makefile
71 * to implement a backend, and we'll document this skeleton here.
73 * A backend is defined by a single name, for example @c BACKENDNAME, that
74 * causes libelektra.so look for its library as @c libelektra-BACKENDNAME.so.
76 * Elektra source code tree includes several backend implementations
77 * (http://germane-software.com/repositories/elektra/trunk/src/backends)
78 * that can also be used as a reference.
86 * Initialize the backend.
87 * This is the first method kdbOpenBackend() calls after dynamically loading
88 * the backend library.
90 * This method is responsible of:
91 * - backend's specific configuration gathering
92 * - all backend's internal structs initialization
93 * - initial setup of all I/O details such as opening a file, connecting to a
96 * @return 0 on success, anything else otherwise.
97 * @see kdbOpenBackend()
101 int kdbOpen_winregistry(KDB *handle) {
102 /* backend initialization logic */
110 * All finalization logic of the backend should go here.
112 * Called prior to unloading the backend dynamic module. Should ensure that no
113 * functions or static/global variables from the module will ever be accessed again.
114 * Should free any memory that the backend no longer needs.
115 * After this call, libelektra.so will unload the backend library, so this is
116 * the point to shutdown any affairs with the storage.
118 * @return 0 on success, anything else otherwise.
122 int kdbClose_winregistry(KDB *handle) {
123 /* free all backend resources and shut it down */
124 return 0; /* success */
130 * Implementation for kdbStatKey() method.
132 * This method is responsible of:
133 * - make necessary I/O to retrieve @p key->name's metadata
134 * - fill the @p key struct with its metadata
136 * @see kdbStatKey() for expected behavior.
139 int kdbStatKey_winregistry(KDB *handle, Key *key) {
140 /* get the most possible key metainfo */
141 return 0; /* success */
146 * Implementation for kdbGetKey() method.
148 * This method is responsible of:
149 * - make necessary I/O to retrieve all @p key->name's value and metadata
150 * - fill the @p key struct with its value and metadata
152 * @see kdbGetKey() for expected behavior.
155 int kdbGetKey_winregistry(KDB *handle, Key *key) {
156 /* fully gets a key */
158 HKEY desiredKey = {0};
162 DWORD sizeval = sizeof(val);
163 char *keyName = NULL;
165 if(!kdbGetRegistryPath(key, rootKey, path, sizeof(path), &keyName))
170 if(err = RegGetValue(rootKey, path, keyName, RRF_RT_REG_SZ|RRF_RT_REG_MULTI_SZ, &type, val, &sizeval) != ERROR_SUCCESS)
172 errno = mapError(err);
175 keySetType(key,KEY_TYPE_STRING);
176 keySetRaw(key, val, strlen(val));
177 /*if((err = RegOpenKeyEx(rootKey, path, 0, KEY_READ,&desiredKey)) != ERROR_SUCCESS)
180 errno = mapError(err);
183 if(RegQueryValueEx(desiredKey, keyName, 0,&type, (LPBYTE)val, &sizeval) != ERROR_SUCCESS)
185 errno = mapError(err);
191 return 0; /* success */
197 * Implementation for kdbSetKey() method.
199 * This method is responsible of:
200 * - check the existence of @p key->name on persistent storage
201 * - prepare the backend to receive a new or updated key
202 * - use value and metadata from @p key to store them in the backend storage
203 * - fill the @p key struct with its value and metadata
205 * @see kdbSetKey() for expected behavior.
208 int kdbSetKey_winregistry(KDB *handle, Key *key) {
209 /* fully sets a key */
211 HKEY desiredKey = {0};
214 char *keyName = NULL;
216 if(!kdbGetRegistryPath(key, rootKey, path, sizeof(path), &keyName))
220 if((err = RegOpenKeyEx(rootKey, path, 0, KEY_READ,&desiredKey)) != ERROR_SUCCESS)
222 /* Error opening key */
223 errno = mapError(err);
226 /* TODO: NOT DELETE VALUE HERE!!! */
227 if((err = RegSet(?)Value(desiredKey, keyName)) != ERROR_SUCCESS)
229 errno = mapError(err);
230 RegCloseKey(desiredKey);
233 RegCloseKey(desiredKey);
234 return 0; /* success */
240 * Implementation for kdbRename() method.
242 * @see kdbRename() for expected behavior.
245 int kdbRename_winregistry(KDB *handle, Key *key, const char *newName) {
246 /* rename a key to another name */
247 return 0; /* success */
254 * Implementation for kdbRemoveKey() method.
256 * @see kdbRemove() for expected behavior.
259 int kdbRemoveKey_winregistry(KDB *handle, const Key *key) {
260 /* remove a key from the database */
262 HKEY desiredKey = {0};
265 char *keyName = NULL;
267 if(!kdbGetRegistryPath(key, rootKey, path, sizeof(path), &keyName))
271 if((err = RegOpenKeyEx(rootKey, path, 0, KEY_READ,&desiredKey)) != ERROR_SUCCESS)
273 /* Error opening key */
274 errno = mapError(err);
277 if((err = RegDeleteValue(desiredKey, keyName)) != ERROR_SUCCESS)
279 errno = mapError(err);
280 RegCloseKey(desiredKey);
283 RegCloseKey(desiredKey);
284 return 0; /* success */
291 * Implementation for kdbGetKeyChildKeys() method.
293 * @see kdbGetKeyChildKeys() for expected behavior.
296 ssize_t kdbGetKeyChildKeys_winregistry(KDB *handle, const Key *parentKey, KeySet *returned, unsigned long options) {
297 /* retrieve multiple hierarchical keys */
298 return (ssize_t)returned->size; /* success */
303 * Implementation for kdbSetKeys() method.
305 * The implementation of this method is optional, and a builtin, probablly
306 * inefficient implementation can be explicitly used when exporting the
307 * backend with kdbBackendExport(), using kdbSetKeys_default().
309 * @see kdbSetKeys() for expected behavior.
312 int kdbSetKeys_winregistry(KDB *handle, KeySet *ks) {
319 * The implementation of this method is optional.
320 * The builtin inefficient implementation will use kdbGetKey() for each
321 * key inside @p interests.
323 * @see kdbMonitorKeys() for expected behavior.
326 uint32_t kdbMonitorKeys_winregistry(KDB *handle, KeySet *interests, uint32_t diffMask,
327 unsigned long iterations, unsigned sleep) {
335 * The implementation of this method is optional.
336 * The builtin inefficient implementation will use kdbGetKey() for
339 * @see kdbMonitorKey() for expected behavior.
342 uint32_t kdbMonitorKey_winregistry(KDB *handle, Key *interest, uint32_t diffMask,
343 unsigned long iterations, unsigned sleep) {
347 KDBEXPORT(BACKENDNAME) {
348 return kdbBackendExport(BACKENDNAME,
349 KDB_BE_OPEN, &kdbOpen_winregistry,
350 KDB_BE_CLOSE, &kdbClose_winregistry,
351 KDB_BE_GETKEY, &kdbGetKey_winregistry,
352 KDB_BE_SETKEY, &kdbSetKey_winregistry,
353 KDB_BE_STATKEY, &kdbStatKey_winregistry,
354 KDB_BE_RENAME, &kdbRename_winregistry,
355 KDB_BE_REMOVEKEY, &kdbRemoveKey_winregistry,
356 KDB_BE_GETCHILD, &kdbGetKeyChildKeys_winregistry,
361 * Calculate the real file name for a key.
363 * @param returned the buffer to return the calculated filename
364 * @param maxSize maximum number of bytes that fit the buffer
365 * @see kdbCalcRelativeFilename()
366 * @return number of bytes written to the buffer, or 0 on error
369 size_t kdbGetRegistryPath(const Key *forKey,HKEY rootkey, char *path, size_t maxSize, char **keyName) {
373 switch (keyGetNamespace(forKey)) {
375 /* Prepare to use the 'system/ *' database */
376 rootkey = HKEY_LOCAL_MACHINE;
377 length = snprintf(path, maxSize, "%s/%s", KDB_REGISTRY_PATH, forKey->key);
381 /* Prepare to use the 'user:????/ *' database */
382 if (forKey->userDomain)
384 /* This is unsupported so far */
385 errno = KDB_ERR_INVALIDKEY;
387 /* FIXME: The Following code should work immediately as soon as getSID is implemented */
388 /*rootkey = HKEY_USERS;
389 sid=getSID(forKey->userDomain);
390 if (!sid) return 0; /* propagate errno
391 length = snprintf(path,maxSize, "%s/%s/%s", sid, KDB_REGISTRY_PATH, forKey->key);*/
395 rootkey = HKEY_CURRENT_USER;
396 length = snprintf(path, maxSize, "%s/%s", KDB_REGISTRY_PATH, forKey->key);
401 errno=KDB_ERR_INVALIDKEY;
405 *keyName = strrchr(path, '/');
411 /* getSID finds the Security identifier of a given username. This is needed to use user:username/ elektra urls */
412 size_t getSID(char *username, char *sid, int size)
417 int mapError(LONG err)
421 case ERROR_ACCESS_DENIED: return KDB_ERR_NOCRED;
423 return KDB_ERR_NOTFOUND;