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 } |