Git init
[pkgs/e/elektra.git] / src / backends / winregistry / winregistry.cpp
1 // winregistry.cpp : Defines the entry point for the DLL application.
2 // $Id$
3
4 #include "winregistry.h"
5 #include <windows.h>
6
7 int mapError(LONG err);
8
9 BOOL APIENTRY DllMain( HANDLE hModule, 
10                        DWORD  ul_reason_for_call, 
11                        LPVOID lpReserved
12                                          )
13 {
14         switch (ul_reason_for_call)
15         {
16         case DLL_PROCESS_ATTACH:
17         case DLL_THREAD_ATTACH:
18         case DLL_THREAD_DETACH:
19         case DLL_PROCESS_DETACH:
20                 break;
21         }
22     return TRUE;
23 }
24
25
26
27 /**
28  * @defgroup backend Elektra framework for pluggable backends
29  * @brief The tactics to create pluggable backends to libelektra.so
30  *
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
33  * implementation.
34  * 
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.
39  * 
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.
43  *
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
46  * different backend.
47  * 
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.
51  * 
52  * The backend implementation must:
53  * @code
54 #include <kdbbackend.h>
55  * @endcode
56  * 
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>
60  * 
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
68  * system.
69  * 
70  * Elektra source code or development package provides a skeleton and Makefile
71  * to implement a backend, and we'll document this skeleton here.
72  * 
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.
75  * 
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.
79  */
80
81
82
83
84
85 /**
86  * Initialize the backend.
87  * This is the first method kdbOpenBackend() calls after dynamically loading
88  * the backend library.
89  *
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
94  *   database, etc
95  *
96  * @return 0 on success, anything else otherwise.
97  * @see kdbOpenBackend()
98  * @see kdbOpen()
99  * @ingroup backend
100  */
101 int kdbOpen_winregistry(KDB *handle) {
102         /* backend initialization logic */
103         return 0;
104 }
105
106
107
108
109 /**
110  * All finalization logic of the backend should go here.
111  * 
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.
117  *
118  * @return 0 on success, anything else otherwise.
119  * @see kdbClose()
120  * @ingroup backend
121  */
122 int kdbClose_winregistry(KDB *handle) {
123         /* free all backend resources and shut it down */
124         return 0; /* success */
125 }
126
127
128
129 /**
130  * Implementation for kdbStatKey() method.
131  *
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
135  *
136  * @see kdbStatKey() for expected behavior.
137  * @ingroup backend
138  */
139 int kdbStatKey_winregistry(KDB *handle, Key *key) {
140         /* get the most possible key metainfo */
141         return 0; /* success */
142 }
143
144
145 /**
146  * Implementation for kdbGetKey() method.
147  *
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
151  *
152  * @see kdbGetKey() for expected behavior.
153  * @ingroup backend
154  */
155 int kdbGetKey_winregistry(KDB *handle, Key *key) {
156         /* fully gets a key */
157         HKEY rootKey = {0};
158         HKEY desiredKey = {0};
159         char path[1024];
160         DWORD type;
161         char val[1024];
162         DWORD sizeval = sizeof(val);
163         char *keyName = NULL;
164         LONG err=0;
165         if(!kdbGetRegistryPath(key, rootKey, path, sizeof(path), &keyName))
166         {
167                 return -1;
168         }
169         
170         if(err = RegGetValue(rootKey, path, keyName, RRF_RT_REG_SZ|RRF_RT_REG_MULTI_SZ, &type, val, &sizeval) != ERROR_SUCCESS)
171         {
172                 errno = mapError(err);
173                 return -1;
174         }
175         keySetType(key,KEY_TYPE_STRING);
176         keySetRaw(key, val, strlen(val));
177         /*if((err = RegOpenKeyEx(rootKey, path, 0, KEY_READ,&desiredKey)) != ERROR_SUCCESS)
178         {
179                 /* Error opening key 
180                 errno = mapError(err);
181                 return -1;
182         }
183         if(RegQueryValueEx(desiredKey, keyName, 0,&type, (LPBYTE)val, &sizeval) != ERROR_SUCCESS)
184         {
185                 errno = mapError(err);
186                 return -1;
187         }*/
188         
189
190
191         return 0; /* success */
192 }
193
194
195
196 /**
197  * Implementation for kdbSetKey() method.
198  *
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
204  *
205  * @see kdbSetKey() for expected behavior.
206  * @ingroup backend
207  */
208 int kdbSetKey_winregistry(KDB *handle, Key *key) {
209         /* fully sets a key */
210         HKEY rootKey = {0};
211         HKEY desiredKey = {0};
212         char path[1024];
213         DWORD type;
214         char *keyName = NULL;
215         LONG err=0;
216         if(!kdbGetRegistryPath(key, rootKey, path, sizeof(path), &keyName))
217         {
218                 return -1;
219         }
220         if((err = RegOpenKeyEx(rootKey, path, 0, KEY_READ,&desiredKey)) != ERROR_SUCCESS)
221         {
222                 /* Error opening key */
223                 errno = mapError(err);
224                 return -1;
225         }
226         /* TODO: NOT DELETE VALUE HERE!!! */
227         if((err = RegSet(?)Value(desiredKey, keyName)) != ERROR_SUCCESS)
228         {
229                 errno = mapError(err);
230                 RegCloseKey(desiredKey);
231                 return -1;
232         }
233         RegCloseKey(desiredKey);
234         return 0;  /* success */
235 }
236
237
238
239 /**
240  * Implementation for kdbRename() method.
241  *
242  * @see kdbRename() for expected behavior.
243  * @ingroup backend
244  */
245 int kdbRename_winregistry(KDB *handle, Key *key, const char *newName) {
246         /* rename a key to another name */
247         return 0; /* success */
248 }
249
250
251
252
253 /**
254  * Implementation for kdbRemoveKey() method.
255  *
256  * @see kdbRemove() for expected behavior.
257  * @ingroup backend
258  */
259 int kdbRemoveKey_winregistry(KDB *handle, const Key *key) {
260         /* remove a key from the database */
261         HKEY rootKey = {0};
262         HKEY desiredKey = {0};
263         char path[1024];
264         DWORD type;
265         char *keyName = NULL;
266         LONG err=0;
267         if(!kdbGetRegistryPath(key, rootKey, path, sizeof(path), &keyName))
268         {
269                 return -1;
270         }
271         if((err = RegOpenKeyEx(rootKey, path, 0, KEY_READ,&desiredKey)) != ERROR_SUCCESS)
272         {
273                 /* Error opening key */
274                 errno = mapError(err);
275                 return -1;
276         }
277         if((err = RegDeleteValue(desiredKey, keyName)) != ERROR_SUCCESS)
278         {
279                 errno = mapError(err);
280                 RegCloseKey(desiredKey);
281                 return -1;
282         }
283         RegCloseKey(desiredKey);
284         return 0;  /* success */
285 }
286
287
288
289
290 /**
291  * Implementation for kdbGetKeyChildKeys() method.
292  *
293  * @see kdbGetKeyChildKeys() for expected behavior.
294  * @ingroup backend
295  */
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 */
299 }
300
301
302 /**
303  * Implementation for kdbSetKeys() method.
304  * 
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().
308  * 
309  * @see kdbSetKeys() for expected behavior.
310  * @ingroup backend
311  */
312 int kdbSetKeys_winregistry(KDB *handle, KeySet *ks) {
313         /* set many keys */
314         return 0;
315 }
316
317
318 /**
319  * The implementation of this method is optional.
320  * The builtin inefficient implementation will use kdbGetKey() for each
321  * key inside @p interests.
322  *
323  * @see kdbMonitorKeys() for expected behavior.
324  * @ingroup backend
325  */
326 uint32_t kdbMonitorKeys_winregistry(KDB *handle, KeySet *interests, uint32_t diffMask,
327                 unsigned long iterations, unsigned sleep) {
328         return 0;
329 }
330
331
332
333 /**
334  *
335  * The implementation of this method is optional.
336  * The builtin inefficient implementation will use kdbGetKey() for
337  * @p interest.
338  *
339  * @see kdbMonitorKey() for expected behavior.
340  * @ingroup backend
341  */
342 uint32_t kdbMonitorKey_winregistry(KDB *handle, Key *interest, uint32_t diffMask,
343                 unsigned long iterations, unsigned sleep) {
344         return 0;
345 }
346
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,
357                 KDB_BE_END);
358 }
359
360 /**
361  * Calculate the real file name for a key.
362  *
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
367  * @ingroup internals
368  */
369 size_t kdbGetRegistryPath(const Key *forKey,HKEY rootkey, char *path, size_t maxSize, char **keyName) {
370         size_t length=0;
371         char *sid = NULL;
372
373         switch (keyGetNamespace(forKey)) {
374                 case KEY_NS_SYSTEM: 
375                         /* Prepare to use the 'system/ *' database */
376                         rootkey = HKEY_LOCAL_MACHINE;
377                         length = snprintf(path, maxSize, "%s/%s", KDB_REGISTRY_PATH, forKey->key);
378                         break;
379
380                 case KEY_NS_USER: 
381                         /* Prepare to use the 'user:????/ *' database */
382                         if (forKey->userDomain) 
383                         {
384                                 /* This is unsupported so far */
385                                 errno = KDB_ERR_INVALIDKEY;
386                                 return 0;
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);*/
392                         }
393                         else
394                         {
395                                 rootkey = HKEY_CURRENT_USER;
396                                 length = snprintf(path, maxSize, "%s/%s", KDB_REGISTRY_PATH, forKey->key);
397                         }
398                         break;
399
400                 default: {
401                         errno=KDB_ERR_INVALIDKEY;
402                         return 0;
403                 }
404         }
405         *keyName = strrchr(path, '/');
406         *keyName = '\0';
407         *keyName++;
408         return length;
409 }
410
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)
413 {
414         return 0;
415 }
416
417 int mapError(LONG err)
418 {
419         switch(err)
420         {
421         case ERROR_ACCESS_DENIED: return KDB_ERR_NOCRED;
422         default:
423                 return KDB_ERR_NOTFOUND;
424         }
425 }
426