src/server/plugins/postgresql/config.c

branch
webdav
changeset 373
f78a585e1a2f
parent 372
1d2538a1ba8f
child 374
77506ec632a4
equal deleted inserted replaced
372:1d2538a1ba8f 373:f78a585e1a2f
28 28
29 #include "config.h" 29 #include "config.h"
30 30
31 #include "../../util/util.h" 31 #include "../../util/util.h"
32 32
33 #include <libxml/tree.h>
34
35 #define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b)
36
37 static int pg_load_ext_dav_config(
38 ServerConfiguration *cfg,
39 pool_handle_t *pool,
40 PgRepository *repo,
41 const char *file);
42
43
33 static const char *sql_get_repository_root = "select resource_id from Resource where parent_id is NULL and nodename = $1 ;"; 44 static const char *sql_get_repository_root = "select resource_id from Resource where parent_id is NULL and nodename = $1 ;";
34 45
35 46
36 // Uses a PGconn to lookup the resource id of the specified root node 47 // Uses a PGconn to lookup the resource id of the specified root node
37 // if the lookup succeeds, the resource id is written to rootid 48 // if the lookup succeeds, the resource id is written to rootid
128 139
129 PgRepository *repo = pool_malloc(pool, sizeof(PgRepository)); 140 PgRepository *repo = pool_malloc(pool, sizeof(PgRepository));
130 ZERO(repo, sizeof(PgRepository)); 141 ZERO(repo, sizeof(PgRepository));
131 142
132 repo->resourcepool = sstrdup_a(&a, cfg_respool); 143 repo->resourcepool = sstrdup_a(&a, cfg_respool);
144 repo->root_resource_id = root_id;
145
146 // check for extended pg dav config
147 if(cfg_dav.length > 0) {
148 // load extended config from config file
149 char *cfg_file_path = cfg_config_file_path(cfg_dav.ptr);
150 if(pg_load_ext_dav_config(cfg, pool, repo, cfg_file_path)) {
151 // error
152 repo = NULL; // no need to cleanup because everything is from the pool
153 }
154 free(cfg_file_path);
155 }
133 156
134 return repo; 157 return repo;
135 } 158 }
159
160 static int pg_ext_get_config(
161 ServerConfiguration *cfg,
162 pool_handle_t *pool,
163 PgRepository *repo,
164 const char *file_path,
165 xmlNode *root);
166 static int pg_ext_get_extension(
167 PgExtParser *ext,
168 pool_handle_t *pool,
169 PgRepository *repo,
170 const char *file_path,
171 xmlNode *ext_node);
172
173 static const char* pg_util_xml_get_text(const xmlNode *elm) {
174 xmlNode *node = elm->children;
175 while(node) {
176 if(node->type == XML_TEXT_NODE) {
177 return (const char*)node->content;
178 }
179 node = node->next;
180 }
181 return NULL;
182 }
183
184 // load additional postgresql webdav config from the specified xml file
185 static int pg_load_ext_dav_config(
186 ServerConfiguration *cfg,
187 pool_handle_t *pool,
188 PgRepository *repo,
189 const char *file_path)
190 {
191 UcxAllocator a = util_pool_allocator(pool);
192
193 // check if the file exists and can be accessed
194 struct stat s;
195 if(stat(file_path, &s)) {
196 if(errno == ENOENT) {
197 log_ereport(LOG_FAILURE, "pg: config file %s not found", file_path);
198 } else {
199 log_ereport(LOG_FAILURE, "pg: cannot access config file %s", file_path);
200 }
201
202 return 1;
203 }
204
205 // prepare PgRepository
206 repo->prop_ext = ucx_map_new_a(&a, 8);
207 if(!repo->prop_ext) {
208 log_ereport(LOG_FAILURE, "pg: cannot load config file: OOM");
209 return 1;
210 }
211
212 // load xml document
213 xmlDoc *doc = xmlReadFile(file_path, NULL, 0);
214 if(!doc) {
215 log_ereport(LOG_FAILURE, "pg: cannot load config file %s", file_path);
216 return 1;
217 }
218
219 // the root element must be <repository>
220 int ret = 0;
221 xmlNode *xml_root = xmlDocGetRootElement(doc);
222 if(xstreq(xml_root->name, "repository")) {
223 // parse config
224 ret = pg_ext_get_config(cfg, pool, repo, file_path, xml_root);
225 } else {
226 log_ereport(LOG_MISCONFIG, "pg: config %s: root element <repository> expected", file_path);
227 ret = 1;
228 }
229 xmlFreeDoc(doc);
230
231 return ret;
232 }
233
234
235
236
237 static int pg_ext_get_config(
238 ServerConfiguration *cfg,
239 pool_handle_t *pool,
240 PgRepository *repo,
241 const char *file_path,
242 xmlNode *root)
243 {
244 xmlNode *node = root->children;
245 int ret = 0;
246
247 PgExtParser parserData;
248 parserData.table_lookup = ucx_map_new(8);
249 parserData.tables = NULL;
250
251 while(node && !ret) {
252 // currently, the only possible config element is <extension>
253 if(node->type == XML_ELEMENT_NODE) {
254 if(xstreq(node->name, "extension")) {
255 ret = pg_ext_get_extension(&parserData, pool, repo, file_path, node);
256 }
257 }
258 node = node->next;
259 }
260
261 // convert parserData
262 if(!ret) {
263 size_t ntables = ucx_list_size(parserData.tables);
264 repo->ntables = ntables;
265 repo->tables = pool_calloc(pool, ntables, sizeof(PgExtTable));
266 if(repo->tables) {
267 int i = 0;
268 UCX_FOREACH(elm, parserData.tables) {
269 PgExtTable *tab = elm->data;
270 repo->tables[i++] = *tab;
271 }
272 } else {
273 ret = 1;
274 }
275
276 }
277
278 // cleanup parser
279 ucx_list_free_content(parserData.tables, free);
280 ucx_list_free(parserData.tables);
281 ucx_map_free(parserData.table_lookup);
282
283 return ret;
284 }
285
286 static int pg_ext_get_extension(
287 PgExtParser *ext,
288 pool_handle_t *pool,
289 PgRepository *repo,
290 const char *file_path,
291 xmlNode *ext_node)
292 {
293 UcxAllocator a = util_pool_allocator(pool);
294
295 xmlNode *node = ext_node->children;
296
297 const char *table = NULL;
298 UcxList *properties = NULL;
299
300 while(node) {
301 if(node->type == XML_ELEMENT_NODE) {
302 if(xstreq(node->name, "table")) {
303 const char *value = pg_util_xml_get_text(node);
304 if(!value) {
305 log_ereport(LOG_MISCONFIG, "pg: config %s: table: missing value", file_path, table);
306 return 1;
307 } else if(table) {
308 log_ereport(LOG_MISCONFIG, "pg: config %s: table %s already set", file_path, table);
309 return 1;
310 }
311 table = value;
312 } else if(xstreq(node->name, "properties")) {
313 // add all child elements to the properties list
314 xmlNode *ps = node->children;
315 while(ps) {
316 if(ps->type == XML_ELEMENT_NODE) {
317 // validate
318 // required: namespace, value
319 if(!ps->ns || !ps->ns->href) {
320 log_ereport(LOG_MISCONFIG, "pg: config %s: property %s: missing namespace", file_path, ps->name);
321 return 1;
322 }
323 const char *value = pg_util_xml_get_text(ps);
324 if(!value) {
325 log_ereport(LOG_MISCONFIG, "pg: config %s: no column specified for property %s", file_path, ps->name);
326 return 1;
327 }
328 properties = ucx_list_append_a(&a, properties, ps);
329 }
330 ps = ps->next;
331 }
332 }
333 }
334 node = node->next;
335 }
336
337 // check if anything is missing
338 if(!table) {
339 log_ereport(LOG_MISCONFIG, "pg: config %s: missing table value for extension", file_path);
340 return 1;
341 }
342 if(!properties) {
343 log_ereport(LOG_MISCONFIG, "pg: config %s: no properties configured for extension", file_path);
344 return 1;
345 }
346
347 // check if the table was already specified
348 if(ucx_map_cstr_get(ext->table_lookup, table)) {
349 log_ereport(LOG_MISCONFIG, "pg: config %s: extension table %s not unique", file_path, table);
350 return 1;
351 }
352 // mark table as used
353 // tabname will be used later, so ist must be allocated in the pool
354 char *tabname = pool_strdup(pool, table);
355 if(!tabname) return 1;
356
357 // exttable is only used temporarily
358 PgExtTable *exttable = malloc(sizeof(PgExtTable));
359 if(!exttable) return 1;
360 exttable->table = tabname;
361 exttable->isused = 0; // not relevant in config
362 ext->tables = ucx_list_append(ext->tables, exttable);
363
364 if(ucx_map_cstr_put(ext->table_lookup, table, table)) {
365 return 1;
366 }
367
368 int tableindex = (int)ucx_list_size(ext->tables);
369 UCX_FOREACH(elm, properties) {
370 xmlNode *ps = elm->data;
371 const char *value = pg_util_xml_get_text(ps);
372
373 PgPropertyStoreExt *ext = pool_malloc(pool, sizeof(PgPropertyStoreExt));
374 if(!ext) {
375 return 1;
376 }
377 ext->tableindex = tableindex;
378 ext->ns = pool_strdup(pool, (const char*)ps->ns->href);
379 ext->name = pool_strdup(pool, (const char*)ps->name);
380 ext->column = pool_strdup(pool, (const char*)value);
381 if(!ext->ns || !ext->name || !ext->column) {
382 return 1;
383 }
384
385 UcxKey key = webdav_property_key(ext->ns, ext->name);
386 int err = ucx_map_put(repo->prop_ext, key, ext);
387 free((void*)key.data);
388 if(err) {
389 return 1;
390 }
391 }
392
393 return 0;
394 }

mercurial