- Add a very preliminary and light libmapistore implementation.
[jelmer/openchange-proposed.git/.git] / mapiproxy / libmapistore / mapistore_backend.c
1 /*
2    OpenChange Storage Abstraction Layer library
3
4    OpenChange Project
5
6    Note: init and load functions have been copied from
7    samba4/source4/param/util.c initially wrote by Jelmer.
8
9    Copyright (C) Jelmer Vernooij 2005-2007
10    Copyright (C) Julien Kerihuel 2009
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16    
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21    
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24  */
25
26 #include <sys/types.h>
27 #include <string.h>
28 #include <dlfcn.h>
29 #include <dirent.h>
30
31 #include "mapistore.h"
32 #include "mapistore_errors.h"
33 #include "mapistore_private.h"
34 #include <libmapi/dlinklist.h>
35
36 #include <util.h>
37 #include <util/debug.h>
38
39 /**
40    \file mapistore_backend.c
41
42    \brief mapistore backends management API
43  */
44
45
46 static struct mstore_backend {
47         struct mapistore_backend        *backend;
48 } *backends = NULL;
49
50 int                                     num_backends;
51
52
53 /**
54    \details Register mapistore backends
55
56    \param _backend pointer to the mapistore backend to register
57
58    \return MAPISTORE_SUCCESS on success
59  */
60 _PUBLIC_ extern int mapistore_backend_register(const void *_backend)
61 {
62         const struct mapistore_backend  *backend = _backend;
63
64         backends = realloc_p(backends, struct mstore_backend, num_backends + 1);
65         if (!backends) {
66                 smb_panic("out of memory in mapistore_backend_register");
67         }
68
69         backends[num_backends].backend = smb_xmemdup(backend, sizeof (*backend));
70         backends[num_backends].backend->name = smb_xstrdup(backend->name);
71
72         num_backends++;
73
74         DEBUG(3, ("MAPISTORE backend '%s' registered\n", backend->name));
75
76         return MAPISTORE_SUCCESS;
77 }
78
79
80 /**
81    \details Return the full path where mapistore backends are
82    installed.
83
84    \return Pointer to the full path where backends are installed.
85  */
86 _PUBLIC_ const char *mapistore_backend_get_installdir(void)
87 {
88         return MAPISTORE_BACKEND_INSTALLDIR;
89 }
90
91
92 /**
93    \details Obtain the backend init function from a shared library
94    file
95
96    \param path full path to the backend shared library
97
98    \return Pointer to the initialization function on success,
99    otherwise NULL.
100  */
101 static init_backend_fn load_backend(const char *path)
102 {
103         void    *handle;
104         void    *init_fn;
105
106         handle = dlopen(path, RTLD_NOW);
107         if (handle == NULL) {
108                 DEBUG(0, ("Unable to open %s: %s\n", path, dlerror()));
109                 return NULL;
110         }
111
112         init_fn = dlsym(handle, MAPISTORE_INIT_MODULE);
113
114         if (init_fn == NULL) {
115                 DEBUG(0, ("Unable to find %s() in %s: %s\n",
116                           MAPISTORE_INIT_MODULE, path, dlerror()));
117                 DEBUG(1, ("Loading mapistore backend '%s' failed\n", path));
118                 dlclose(handle);
119                 return NULL;
120         }
121
122         return (init_backend_fn) init_fn;
123 }
124
125
126 /**
127    \details Load backends from specified directory
128
129    \param mem_ctx pointer to the memory context
130    \param pointer to the backends shared library folder
131
132    \return allocated array of functions pointers to initialization
133    functions on success, otherwise NULL.
134  */
135 static init_backend_fn *load_backends(TALLOC_CTX *mem_ctx, const char *path)
136 {
137         DIR             *dir;
138         struct dirent   *entry;
139         char            *filename;
140         int             success = 0;
141         init_backend_fn *ret;
142
143         ret = talloc_array(mem_ctx, init_backend_fn, 2);
144         ret[0] = NULL;
145
146         dir = opendir(path);
147         if (dir == NULL) {
148                 talloc_free(ret);
149                 return NULL;
150         }
151
152         while ((entry = readdir(dir))) {
153                 if (ISDOT(entry->d_name) || ISDOTDOT(entry->d_name)) {
154                         continue;
155                 }
156                 
157                 filename = talloc_asprintf(mem_ctx, "%s/%s", path, entry->d_name);
158                 ret[success] = load_backend(filename);
159                 if (ret[success]) {
160                         ret = talloc_realloc(mem_ctx, ret, init_backend_fn, success + 2);
161                         success++;
162                         ret[success] = NULL;
163                 }
164
165                 talloc_free(filename);
166         }
167
168         closedir(dir);
169
170         return ret;
171 }
172
173
174 /**
175    \details Load the initialization functions from backends DSO
176
177    \param mem_ctx pointer to the memory context
178    \param path pointer to the backend's DSO folder
179
180    \return allocated array of functions pointers to initialization
181    functions on success, otherwise NULL.
182  */
183 _PUBLIC_ init_backend_fn *mapistore_backend_load(TALLOC_CTX *mem_ctx, const char *path)
184 {
185         if (!path) {
186                 path = mapistore_backend_get_installdir();
187         }
188
189         return load_backends(mem_ctx, path);
190 }
191
192
193 /**
194    \details Run specified initialization functions.
195
196    \param fns pointer to an array of mapistore backends initialization
197    functions
198
199    \return true on success, otherwise false
200  */
201 _PUBLIC_ bool mapistore_backend_run_init(init_backend_fn *fns)
202 {
203         int                             i;
204         bool                            ret = true;
205
206         if (fns == NULL) {
207                 return true;
208         }
209
210         for (i = 0; fns[i]; i++) {
211                 ret &= (bool)fns[i]();
212         }
213
214         return ret;
215 }
216
217
218 /**
219    \details Initialize mapistore backends
220
221    \param mem_ctx pointer to the memory context
222    \param path pointer to folder where mapistore backends are
223    installed
224
225    \return MAPISTORE_SUCCESS on success, otherwise
226    MAPISTORE_ERR_BACKEND_INIT
227  */
228 int mapistore_backend_init(TALLOC_CTX *mem_ctx, const char *path)
229 {
230         init_backend_fn                 *ret;
231         bool                            status;
232         int                             retval;
233         int                             i;
234
235         ret = mapistore_backend_load(mem_ctx, path);
236         status = mapistore_backend_run_init(ret);
237         talloc_free(ret);
238
239         for (i = 0; i < num_backends; i++) {
240                 if (backends[i].backend) {
241                         DEBUG(3, ("MAPISTORE backend '%s' loaded\n", backends[i].backend->name));
242                         retval = backends[i].backend->init();
243                 }
244         }
245
246         return (status != true) ? MAPISTORE_SUCCESS : MAPISTORE_ERR_BACKEND_INIT;
247 }
248
249
250 /**
251    \details Create backend context
252
253    \param mem_ctx pointer to the memory context
254    \param namespace the backend namespace
255    \param uri the backend parameters which can be passes inline
256
257    \return a valid backend_context pointer on success, otherwise NULL
258  */
259 struct backend_context *mapistore_backend_create_context(TALLOC_CTX *mem_ctx, const char *namespace, 
260                                                          const char *uri)
261 {
262         struct backend_context          *context;
263         int                             retval;
264         bool                            found;
265         void                            *private_data = NULL;
266         int                             i;
267
268         DEBUG(0, ("namespace is %s and backend_uri is '%s'\n", namespace, uri));
269         for (i = 0; i < num_backends; i++) {
270                 if (backends[i].backend->namespace && 
271                     !strcmp(namespace, backends[i].backend->namespace)) {
272                         found = true;
273                         retval = backends[i].backend->create_context(mem_ctx, uri, &private_data);
274                         if (retval != MAPISTORE_SUCCESS) {
275                                 return NULL;
276                         }
277
278                         break;
279                 }
280         }
281         if (found == false) {
282                 DEBUG(0, ("MAPISTORE: no backend with namespace '%s' is available\n", namespace));
283                 return NULL;
284         }
285
286         context = talloc_zero(mem_ctx, struct backend_context);
287         context->backend = backends[i].backend;
288         context->private_data = private_data;
289         talloc_steal(context, context->private_data);
290
291         return context;
292 }
293
294
295 /**
296    \details Delete a context from the specified backend
297
298    \param bctx pointer to the backend context
299
300    \return MAPISTORE_SUCCESS on success, otherwise MAPISTORE error
301  */
302 _PUBLIC_ int mapistore_backend_delete_context(struct backend_context *bctx)
303 {
304         if (!bctx->backend->delete_context) return MAPISTORE_ERROR;
305
306         return bctx->backend->delete_context(bctx->private_data);
307 }