src/server/daemon/config.c

changeset 385
a1f4cb076d2f
parent 373
f78a585e1a2f
child 388
30d29ef5b79a
--- a/src/server/daemon/config.c	Tue Aug 13 22:14:32 2019 +0200
+++ b/src/server/daemon/config.c	Sat Sep 24 16:26:10 2022 +0200
@@ -48,6 +48,7 @@
 #include "threadpools.h"
 #include "ldap_auth.h"
 #include "configmanager.h"
+#include "resourcepool.h"
 
 #include "vserver.h"
 #include "../util/pblock.h"
@@ -55,10 +56,13 @@
 #include "../util/atomic.h"
 #include "ucx/buffer.h"
 
-pool_handle_t *cfg_pool;
+pool_handle_t *init_pool;
 
-// TODO: Funktion für ConfigDirective -> directive
-// TODO: Funktion für UcxList parameter list -> pblock
+char* cfg_config_file_path(const char *file) {
+    sstr_t base = ST("config/");
+    sstr_t path = sstrcat(2, base, scstr(file));
+    return path.ptr;
+}
 
 int load_init_conf(char *file) {
     log_ereport(LOG_VERBOSE, "load_init_conf");
@@ -70,14 +74,14 @@
     }
     UcxAllocator *mp = cfg->parser.mp;
 
-    cfg_pool = pool_create(); // one pool for one Configuration
+    init_pool = pool_create(); // one pool for one Configuration
     UcxList *dirs = cfg->directives;
     while(dirs != NULL) {
         ConfigDirective *dir = dirs->data;
 
         /* create NSAPI directive */
         directive *d = malloc(sizeof(directive));
-        d->param = pblock_create_pool(cfg_pool, 8);
+        d->param = pblock_create_pool(init_pool, 8);
         UcxList *param = cfg_param_list(dir->value, mp);
         while(param != NULL) {
             ConfigParam *p = param->data;
@@ -127,19 +131,34 @@
     return 0;
 }
 
-ServerConfiguration* load_server_conf(ServerConfiguration *old, char *file) {
+ServerConfiguration* load_server_conf(char *file) {
     log_ereport(LOG_VERBOSE, "load_server_conf");
 
-    ServerConfig *serverconf = load_server_config(file);
-    if(serverconf == NULL) {
+    ServerConfig *serverconf = serverconfig_load(file);
+    if(!serverconf) {
         log_ereport(LOG_FAILURE, "Cannot load server.conf");
+        return NULL;
     }
-    ServerConfiguration *serverconfig = calloc(1, sizeof(ServerConfiguration));
+    
+    pool_handle_t *pool = pool_create();
+    
+    
+    ServerConfiguration *serverconfig = pool_calloc(pool, 1, sizeof(ServerConfiguration));
     serverconfig->ref = 1;
-    serverconfig->pool = pool_create();
+    serverconfig->pool = pool;
+    
+    UcxAllocator allocator = util_pool_allocator(serverconfig->pool);
+    serverconfig->a = pool_malloc(pool, sizeof(UcxAllocator));
+    *serverconfig->a = allocator;
+    
     serverconfig->listeners = NULL;
-    serverconfig->host_vs = ucx_map_new(16);
-    serverconfig->authdbs = ucx_map_new(16);
+    serverconfig->host_vs = ucx_map_new_a(&allocator, 16);
+    serverconfig->authdbs = ucx_map_new_a(&allocator, 16);
+    serverconfig->resources = ucx_map_new_a(&allocator, 16);
+    serverconfig->dav = ucx_map_new_a(&allocator, 16);
+    
+    
+    
     // TODO: init serverconfig stuff
     
     
@@ -161,49 +180,54 @@
      */
     
     // init logfile first
-    UcxList *lfl = ucx_map_sstr_get(serverconf->objects, sstrn("LogFile", 7));
-    if(lfl != NULL) {
-        ServerConfigObject *logobj = lfl->data;
-        if(logobj == NULL) {
+    UcxList *list = NULL;
+    
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("LogFile"));
+    if(list) {
+        ConfigNode *logobj = list->data;
+        if(!logobj) {
             // error
-            return NULL;
+            return NULL; // TODO: fix memory leak
         }
         
         int ret = cfg_handle_logfile(serverconfig, logobj);
         if(ret != 0) {
             // cannot initialize log file
-            return NULL;
+            return NULL; // TODO: fix memory leak
         }
     } else {
         // horrible error
         return NULL;
     }
+    ucx_list_free(list);
      
-    UcxList *list = ucx_map_sstr_get(serverconf->objects, sstrn("Runtime", 7));
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Runtime"));
     UCX_FOREACH(elm, list) {
-        ServerConfigObject *scfgobj = elm->data;
-        if(cfg_handle_runtime(serverconfig, scfgobj)) {
+        ConfigNode *runtimeobj = elm->data;
+        if(cfg_handle_runtime(serverconfig, runtimeobj)) {
             // error
             return NULL;
         }
     }
+    ucx_list_free(list);
     
-    list = ucx_map_sstr_get(serverconf->objects, sstrn("Threadpool", 10));
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Threadpool"));
     UCX_FOREACH(elm, list) {
         if(cfg_handle_threadpool(serverconfig, elm->data)) {
             return NULL;
         }
     }
+    ucx_list_free(list);
     // check thread pool config
     if(check_thread_pool_cfg() != 0) {
         /* critical error */
         return NULL;
     }
     
-    list = ucx_map_sstr_get(serverconf->objects, sstrn("EventHandler", 12));
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("EventHandler"));
     UCX_FOREACH(elm, list) {
         if(cfg_handle_eventhandler(
-                serverconfig, (ServerConfigObject*)elm->data)) {
+                serverconfig, elm->data)) {
             // error            
             return NULL;
         }
@@ -213,39 +237,59 @@
         /* critical error */
         return NULL;
     }
+    ucx_list_free(list);
     
-    list = ucx_map_sstr_get(serverconf->objects, sstrn("AccessLog", 9));
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("AccessLog"));
     UCX_FOREACH(elm, list) {
-        ServerConfigObject *scfgobj = elm->data;
+        ConfigNode *scfgobj = elm->data;
         if(cfg_handle_accesslog(serverconfig, scfgobj)) {
             return NULL;
         }
     }
+    ucx_list_free(list);
     
-    list = ucx_map_sstr_get(serverconf->objects, sstrn("AuthDB", 6));
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("AuthDB"));
+    UCX_FOREACH(elm, list) {
+        ConfigNode *scfgobj = elm->data;
+        if(cfg_handle_authdb(serverconfig, scfgobj)) {
+            return NULL;
+        }
+    }
+    ucx_list_free(list);
+    
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Listener"));
     UCX_FOREACH(elm, list) {
-        ServerConfigObject *scfgobj = elm->data;
-        if(cfg_handle_authdb(serverconfig, scfgobj)) {
+        ConfigNode *scfgobj = elm->data;
+        if(cfg_handle_listener(serverconfig, scfgobj)) {
+            return NULL;
+        }
+    }
+    ucx_list_free(list);
+    
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("VirtualServer"));
+    UCX_FOREACH(elm, list) {
+        ConfigNode *scfgobj = elm->data;
+        if(cfg_handle_vs(serverconfig, scfgobj)) {
+            return NULL;
+        }
+    }
+    ucx_list_free(list);
+    
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("ResourcePool"));
+    UCX_FOREACH(elm, list) {
+        ConfigNode *scfgobj = elm->data;
+        if(cfg_handle_resourcepool(serverconfig, scfgobj)) {
             return NULL;
         }
     }
     
-    list = ucx_map_sstr_get(serverconf->objects, sstrn("Listener", 8));
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Dav"));
     UCX_FOREACH(elm, list) {
-        ServerConfigObject *scfgobj = elm->data;
-        if(cfg_handle_listener(serverconfig, scfgobj)) {
+        ConfigNode *scfgobj = elm->data;
+        if(cfg_handle_dav(serverconfig, scfgobj)) {
             return NULL;
         }
     }
-    
-    list = ucx_map_sstr_get(serverconf->objects, sstrn("VirtualServer", 13));
-    UCX_FOREACH(elm, list) {
-        ServerConfigObject *scfgobj = elm->data;
-        if(cfg_handle_vs(serverconfig, scfgobj)) {
-            return NULL;
-        }
-    }
-    
 
     // set VirtualServer for all listeners
     UcxList *ls = serverconfig->listeners;
@@ -268,7 +312,8 @@
         ls = ls->next;
     }
     
-    free_server_config(serverconf);
+    serverconfig_free(serverconf);
+    
     return serverconfig;
 }
 
@@ -279,8 +324,7 @@
 void cfg_unref(ServerConfiguration *cfg) {
     uint32_t ref = ws_atomic_dec32(&cfg->ref);
     if(ref == 0) {
-        // TODO: free configuration
-        printf("free ServerConfiguration %"PRIxPTR"\n", (intptr_t)cfg);
+        pool_destroy(cfg->pool);
     }
 }
 
@@ -289,53 +333,36 @@
     
 }
 
-int cfg_handle_runtime(ServerConfiguration *cfg, ServerConfigObject *obj) {
-    sstr_t user = cfg_directivelist_get_str(obj->directives, sstr("User"));
+int cfg_handle_runtime(ServerConfiguration *cfg, ConfigNode *obj) { 
+    scstr_t user = serverconfig_directive_value(obj, SC("User"));
     if(user.ptr) {
-        cfg->user = sstrdup_pool(cfg->pool, user);
+        cfg->user = sstrdup_a(cfg->a, user);
     }
-    sstr_t tmp = cfg_directivelist_get_str(obj->directives, sstr("Temp"));
+    scstr_t tmp = serverconfig_directive_value(obj, SC("Temp"));
     if(tmp.ptr) {
-        cfg->tmp = sstrdup_pool(cfg->pool, tmp);
+        cfg->tmp = sstrdup_a(cfg->a, tmp);
     } else {
+        // TODO: do this check after all config loading is done
         log_ereport(LOG_MISCONFIG, "no temporary directory specified");
         return -1;
     }
     
     // mime file
-    sstr_t mf = cfg_directivelist_get_str(obj->directives, sstr("MimeFile"));  
-    sstr_t base = sstr("config/"); 
+    scstr_t mf = serverconfig_directive_value(obj, SC("MimeFile"));  
+    scstr_t base = SC("config/"); 
     sstr_t file = sstrcat(2, base, mf);
     
-    ConfigFile *f = cfgmgr_get_file(file);
-    if(f == NULL) {
-        f = malloc(sizeof(ConfigFile));
-        f->data = NULL;
-        f->file = sstrdup(file);
-        f->reload = mime_conf_reload;
-        f->last_modified = 0;
-        
-        // load the file content
-        //f->reload(f, cfg);
-        if(cfgmgr_reload_file(f, cfg, NULL)) {
-            free(f->file.ptr);
-            free(f);
-            
-            free(file.ptr);
-            return -1;
-        }
-        cfgmgr_attach_file(f);
+    if(mime_conf_load(cfg, file)) {
+        return -1;
     }
     
-    cfg->mimetypes = f->data;
-    
     free(file.ptr);
     return 0;
 }
 
-int cfg_handle_logfile(ServerConfiguration *cfg, ServerConfigObject *obj) {
-    sstr_t file = cfg_directivelist_get_str(obj->directives, sstr("File"));
-    sstr_t lvl = cfg_directivelist_get_str(obj->directives, sstr("Level"));
+int cfg_handle_logfile(ServerConfiguration *cfg, ConfigNode *obj) {
+    scstr_t file = serverconfig_directive_value(obj, SC("File"));
+    scstr_t lvl = serverconfig_directive_value(obj, SC("Level"));
     
     if(file.ptr == NULL || lvl.ptr == NULL) {
         /* missing log file parameters */
@@ -343,21 +370,18 @@
     }
     
     LogConfig logcfg;
-    logcfg.file = sstrdup(file).ptr;
-    logcfg.level = sstrdup(lvl).ptr;
+    logcfg.file = file.ptr;
+    logcfg.level = lvl.ptr;
     logcfg.log_stdout = 0;
     logcfg.log_stderr = 0;
     /* TODO: stdout, stderr config */
     
     int ret = init_log_file(&logcfg);
-    
-    free(logcfg.file);
-    free(logcfg.level);
 
     return ret;
 }
 
-int cfg_handle_threadpool(ServerConfiguration *cfg, ServerConfigObject *obj) {
+int cfg_handle_threadpool(ServerConfiguration *cfg, ConfigNode *obj) {
     ThreadPoolConfig poolcfg;
     poolcfg.min_threads = 4;
     poolcfg.min_threads = 4;
@@ -365,21 +389,11 @@
     poolcfg.queue_size = 64;
     poolcfg.stack_size = 262144;
     
-    sstr_t name = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Name"));
-    sstr_t min = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("MinThreads"));
-    sstr_t max = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("MaxThreads"));
-    sstr_t stack = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("StackSize"));
-    sstr_t queue = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("QueueSize"));
+    scstr_t name  = serverconfig_directive_value(obj, SC("Name"));
+    scstr_t min   = serverconfig_directive_value(obj, SC("MinThreads"));
+    scstr_t max   = serverconfig_directive_value(obj, SC("MaxThreads"));
+    scstr_t stack = serverconfig_directive_value(obj, SC("StackSize"));
+    scstr_t queue = serverconfig_directive_value(obj, SC("QueueSize"));
     // TODO: Type
     
     if(name.length == 0) {
@@ -388,27 +402,41 @@
     }
     
     if(min.length != 0) {
-        min = sstrdup(min);
-        poolcfg.min_threads = atoi(min.ptr);
-        free(min.ptr);
+        int64_t value;
+        if(util_strtoint(min.ptr, &value)) {
+            poolcfg.min_threads = value;
+        } else {
+            log_ereport(LOG_MISCONFIG, "Threadpool: MinThreads not an integer");
+            return 1;
+        }
     }
     
     if(max.length != 0) {
-        max = sstrdup(max);
-        poolcfg.max_threads = atoi(max.ptr);
-        free(max.ptr);
+        int64_t value;
+        if(util_strtoint(max.ptr, &value)) {
+            poolcfg.max_threads = value;
+        } else {
+            log_ereport(LOG_MISCONFIG, "Threadpool: MaxThreads not an integer");
+            return 1;
+        }
     }
     
     if(stack.length != 0) {
-        stack = sstrdup(stack);
-        poolcfg.stack_size = atoi(stack.ptr);
-        free(stack.ptr);
+        int64_t value;
+        if(util_strtoint(stack.ptr, &value)) {
+            poolcfg.stack_size = value;
+        } else {
+            log_ereport(LOG_MISCONFIG, "Threadpool: StackSize not an integer");
+        }
     }
     
     if(queue.length != 0) {
-        queue = sstrdup(queue);
-        poolcfg.queue_size = atoi(queue.ptr);
-        free(queue.ptr);
+        int64_t value;
+        if(util_strtoint(queue.ptr, &value)) {
+            poolcfg.queue_size = value;
+        } else {
+            log_ereport(LOG_MISCONFIG, "Threadpool: QueueSize not an integer");
+        }
     }
     
     create_threadpool(name, &poolcfg);
@@ -416,32 +444,49 @@
     return 0;
 }
 
-int cfg_handle_eventhandler(ServerConfiguration *c, ServerConfigObject *obj) {
+#define EV_MAX_THREADS 2048
+int cfg_handle_eventhandler(ServerConfiguration *c, ConfigNode *obj) {
     EventHandlerConfig evcfg;
     
-    sstr_t name      = cfg_directivelist_get_str(obj->directives, sstr("Name"));
-    sstr_t threads   = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Threads"));
-    sstr_t isdefault = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Default"));
+    scstr_t name      = serverconfig_directive_value(obj, SC("Name"));
+    scstr_t threads   = serverconfig_directive_value(obj, SC("Threads"));
+    scstr_t isdefault = serverconfig_directive_value(obj, SC("Default"));
     
     evcfg.name = name;
     
-    sstr_t s = sstrdup(threads);
-    evcfg.nthreads = atoi(s.ptr);
-    free(s.ptr);
+    int64_t value;
+    if(!util_strtoint(threads.ptr, &value)) {
+        log_ereport(LOG_MISCONFIG, "EventHandler: Threads: '%s' is not an integer", threads.ptr);
+        return 1;
+    }
+    if(value < 1 || value > EV_MAX_THREADS) {
+        log_ereport(LOG_MISCONFIG, "EventHandler: Invalid number of threads (1 .. %d)", EV_MAX_THREADS);
+        return 1;
+    }
+    
+    evcfg.nthreads = value;
     
     evcfg.isdefault = util_getboolean(isdefault.ptr, 0);
     
     return create_event_handler(&evcfg);
 }
 
-int cfg_handle_accesslog(ServerConfiguration *cfg, ServerConfigObject *obj) {
+int cfg_handle_resourcepool(ServerConfiguration *cfg, ConfigNode *obj) {
+    scstr_t name = serverconfig_directive_value(obj, SC("Name"));
+    scstr_t type = serverconfig_directive_value(obj, SC("Type"));
+    
+    int ret = 0;
+    if(resourcepool_new(cfg, type, name, obj)) {
+        ret = 1;
+    }
+    
+    return ret;
+}
+
+int cfg_handle_accesslog(ServerConfiguration *cfg, ConfigNode *obj) {
     // TODO: use a name to identify the log file
     
-    sstr_t file = cfg_directivelist_get_str(obj->directives, sstr("File"));
+    scstr_t file = serverconfig_directive_value(obj, SC("File"));
     if(file.ptr == NULL) {
         return 0;
     }
@@ -456,10 +501,10 @@
         return 0;
     }
     AccessLog *log = pool_malloc(cfg->pool, sizeof(AccessLog));
-    log->file = sstrdup_pool(cfg->pool, file);
+    log->file = sstrdup_a(cfg->a, file);
     log->format = format;
     log->log = log_file;
-    cfg->logfiles = ucx_list_append(cfg->logfiles, log);
+    cfg->logfiles = ucx_list_append_a(cfg->a, cfg->logfiles, log);
     
     if(!cfg->default_log) {
         cfg->default_log = log;
@@ -468,61 +513,31 @@
     return 0;
 }
 
-int cfg_handle_authdb(ServerConfiguration *cfg, ServerConfigObject *obj) {
-    sstr_t name = cfg_directivelist_get_str(obj->directives, sstr("Name"));
-    sstr_t type = cfg_directivelist_get_str(obj->directives, sstr("Type"));
+int cfg_handle_authdb(ServerConfiguration *cfg, ConfigNode *obj) {
+    scstr_t name = serverconfig_directive_value(obj, SC("Name"));
+    scstr_t type = serverconfig_directive_value(obj, SC("Type"));
+    
+    AuthDB *authdb = NULL;
     
     if(!sstrcmp(type, sstr("ldap"))) {
         LDAPConfig conf;
         
-        sstr_t host = cfg_directivelist_get_str(
-                obj->directives,
-                sstr("Host"));
-        sstr_t port = cfg_directivelist_get_str(
-                obj->directives,
-                sstr("Port"));
-        sstr_t basedn = cfg_directivelist_get_str(
-                obj->directives,
-                sstr("BaseDN"));
-        sstr_t binddn = cfg_directivelist_get_str(
-                obj->directives,
-                sstr("BindDN"));
-        sstr_t basepw = cfg_directivelist_get_str(
-                obj->directives,
-                sstr("BindPW"));
-        
-        host = sstrdup(host);
-        port = sstrdup(port);
-        basedn = sstrdup(basedn);
-        binddn = sstrdup(binddn);
-        basepw = sstrdup(basepw);
+        scstr_t host = serverconfig_directive_value(obj, SC("Host"));
+        scstr_t port = serverconfig_directive_value( obj, SC("Port"));
+        scstr_t basedn = serverconfig_directive_value(obj, SC("BaseDN"));
+        scstr_t binddn = serverconfig_directive_value(obj, SC("BindDN"));
+        scstr_t basepw = serverconfig_directive_value(obj, SC("BindPW"));
         
-        conf.hostname = host.ptr;
+        conf.hostname = sstrdup_a(cfg->a, host).ptr;
         conf.port = atoi(port.ptr);
-        conf.basedn = basedn.ptr;
-        conf.binddn = binddn.ptr;
-        conf.bindpw = basepw.ptr;
-        
-        name = sstrdup(name);
-        
-        AuthDB *authdb = create_ldap_authdb(name.ptr, &conf);
-        ucx_map_sstr_put(cfg->authdbs, name, authdb);
+        conf.basedn = sstrdup_a(cfg->a, basedn).ptr;
+        conf.binddn = sstrdup_a(cfg->a, binddn).ptr;
+        conf.bindpw = sstrdup_a(cfg->a, basepw).ptr;
         
-        // TODO: create_ldap_authdb should copy the strings
-        /*
-        free(host.ptr);
-        free(port.ptr);
-        free(basedn.ptr);
-        free(binddn.ptr);
-        free(basepw.ptr);
-        free(name.ptr);
-        */
-        
+        authdb = create_ldap_authdb(cfg, name.ptr, &conf);      
     } else if(!sstrcmp(type, sstr("keyfile"))) {
         // we only need the file parameter
-        sstr_t file = cfg_directivelist_get_str(
-                obj->directives,
-                sstr("File"));
+        scstr_t file = serverconfig_directive_value(obj, SC("File"));
         if(file.length == 0) {
             log_ereport(
                     LOG_MISCONFIG,
@@ -531,67 +546,55 @@
         }
         
         // load keyfile
-        ConfigFile *f = cfgmgr_get_file(file);
-        if(f == NULL) {
-            f = malloc(sizeof(ConfigFile));
-            f->data = NULL;
-            f->file = sstrdup(file);
-            f->reload = keyfile_reload;
-            f->last_modified = 0;
-            //f->reload(f, cfg);
-            if(cfgmgr_reload_file(f, cfg, NULL)) {
-                free(f->file.ptr);
-                free(f);
-                return -1;
-            }
-            cfgmgr_attach_file(f);
-        }
-        
-        // add keyfile authdb
-        Keyfile *keyfile = f->data;
-        keyfile->authdb.name = sstrdup(name).ptr;
-        ucx_map_sstr_put(cfg->authdbs, name, keyfile);
+        authdb = keyfile_load(cfg, file);
     }
 
+    if(authdb) {
+        if(ucx_map_sstr_put(cfg->authdbs, name, authdb)) {
+            return -1;
+        }
+    }
+    
     return 0;
 }
 
-int cfg_handle_listener(ServerConfiguration *cfg, ServerConfigObject *obj) {
+int cfg_handle_listener(ServerConfiguration *cfg, ConfigNode *obj) {
     ListenerConfig lc;
     ZERO(&lc, sizeof(ListenerConfig));
     lc.cfg = cfg;
     lc.port = 8080;
     lc.nacceptors = 1;
     
+    scstr_t name = serverconfig_directive_value(obj, SC("Name"));
+    scstr_t port = serverconfig_directive_value(obj, SC("Port"));
+    scstr_t vs   = serverconfig_directive_value(obj, SC("DefaultVS"));
+    scstr_t thrp = serverconfig_directive_value(obj, SC("Threadpool"));
+    scstr_t blck = serverconfig_directive_value(obj, SC("BlockingIO"));
+    
     // TODO: use sstrdup_pool?
-    lc.name = sstrdup(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Name")));
-    lc.port = atoi(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Port")).ptr);
-    lc.vs = sstrdup(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("DefaultVS")));
-    lc.threadpool = sstrdup(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Threadpool")));
-    
-    sstr_t blockingio = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("BlockingIO"));
-    if(blockingio.ptr) {
-        lc.blockingio = util_getboolean_s(blockingio, WS_FALSE);
+    int64_t port_value;
+    if(!util_strtoint(port.ptr, &port_value)) {
+        log_ereport(LOG_MISCONFIG, "Listener: Invalid argument for parameter 'Port': '%s'", port.ptr);
+        return 1;
+    }
+    if(port_value < 1 || port_value > 65535) {
+        log_ereport(LOG_MISCONFIG, "Listener: Port number out of range (1 .. 65535)");
+        return 1;
     }
     
-    sstr_t ssl = cfg_directivelist_get_str(obj->directives, S("SSL"));
+    lc.name = sstrdup(name);
+    lc.port = port_value;
+    lc.vs = sstrdup(vs);
+    lc.threadpool = sstrdup(thrp);
+    
+    lc.blockingio = util_getboolean_s(blck, WS_FALSE);
+    
+    scstr_t ssl = serverconfig_directive_value(obj, SC("SSL"));
     if(util_getboolean_s(ssl, WS_FALSE)) {
-        sstr_t cert = cfg_directivelist_get_str(obj->directives, S("Cert"));
-        sstr_t privkey = cfg_directivelist_get_str(obj->directives, S("Key"));
-        sstr_t chain = cfg_directivelist_get_str(obj->directives, S("CertChain"));
-        sstr_t disableprot = cfg_directivelist_get_str(
-                obj->directives,
-                S("SSLDisableProtocol"));
+        scstr_t cert        = serverconfig_directive_value(obj, SC("Cert"));
+        scstr_t privkey     = serverconfig_directive_value(obj, SC("Key"));
+        scstr_t chain       = serverconfig_directive_value(obj, SC("CertChain"));
+        scstr_t disableprot = serverconfig_directive_value(obj, SC("SSLDisableProtocol"));
         
         WSBool config_ok = WS_TRUE;
         // TODO: log error
@@ -628,84 +631,50 @@
         return 1;
     }
     
-    listener->default_vs.vs_name = lc.vs.ptr;
-    cfg->listeners = ucx_list_append(cfg->listeners, listener); 
+    listener->default_vs.vs_name = sstrdup_a(cfg->a, lc.vs).ptr;
+    cfg->listeners = ucx_list_append_a(cfg->a, cfg->listeners, listener); 
     
     return 0;
 }
 
-int cfg_handle_vs(ServerConfiguration *cfg, ServerConfigObject *obj) {
+int cfg_handle_vs(ServerConfiguration *cfg, ConfigNode *obj) {
     VirtualServer *vs = vs_new();
 
-    vs->name = sstrdup(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Name")));
-    vs->host = sstrdup(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Host")));
-    vs->document_root = sstrdup(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("DocRoot")));
-    sstr_t objfile = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("ObjectFile"));
-    sstr_t aclfile = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("ACLFile"));
+    vs->name = sstrdup_a(cfg->a, serverconfig_directive_value(obj, SC("Name")));
+    vs->host = sstrdup_a(cfg->a, serverconfig_directive_value(obj, SC("Host")));
+    vs->document_root = sstrdup_a(cfg->a, serverconfig_directive_value(obj, SC("DocRoot")));
+    
+    scstr_t objfile = serverconfig_directive_value(obj, SC("ObjectFile"));
+    scstr_t aclfile = serverconfig_directive_value(obj, SC("ACLFile"));
     
     // load the object config file
     sstr_t base = sstr("config/");
     sstr_t file = sstrcat(2, base, objfile);
-    file = sstrcat(2, base, objfile);
+    // sstrcat with allocator because we want to keep the string
+    file = sstrcat_a(cfg->a, 2, base, objfile);
 
-    // the file is managed by the configuration manager
-    ConfigFile *f = cfgmgr_get_file(file);
-    if(f == NULL) {
-        f = malloc(sizeof(ConfigFile));
-        f->data = NULL;
-        f->file = sstrdup(file);
-        f->reload = object_conf_reload;
-        f->last_modified = 0;
-        //f->reload(f, cfg);
-        if(cfgmgr_reload_file(f, cfg, NULL)) {
-            free(f->file.ptr);
-            free(f);
-            
-            free(file.ptr);
-            return -1;
-        }
-        cfgmgr_attach_file(f);
+    HTTPObjectConfig *httpobj = objconf_load(cfg, file);
+    if(!httpobj) {
+        return -1;
     }
-    vs->objectfile = sstrdup(file);
-    vs->objects = (HTTPObjectConfig*)f->data;
-    free(file.ptr);
+    vs->objectfile = file;
+    vs->objects = httpobj;
     
     
     // load acl config file
     file = sstrcat(2, base, aclfile);
     
-    ConfigFile *aclf = cfgmgr_get_file(file);
-    if(aclf == NULL) {
-        aclf = malloc(sizeof(ConfigFile));
-        aclf->data = NULL;
-        aclf->file = sstrdup(file);
-        aclf->reload = acl_conf_reload;
-        aclf->last_modified = 0;
-        //aclf->reload(aclf, cfg);
-        if(cfgmgr_reload_file(aclf, cfg, NULL)) {
-            free(aclf->file.ptr);
-            free(aclf);
-            
-            free(file.ptr);
-            return -1;
-        }
-        cfgmgr_attach_file(aclf);
+    ACLData *acldata = acl_conf_load(cfg, file);
+    if(!acldata) {
+        return -1;
     }
-    vs->acls = aclf->data;
+    vs->acls = acldata;
+    
     free(file.ptr);
     
+    
     // set the access log for the virtual server
-    // TODO: don't use always the default
+    // TODO: don't always use the default
     vs->log = cfg->default_log;
 
     ucx_map_sstr_put(cfg->host_vs, vs->host, vs);
@@ -713,54 +682,130 @@
     return 0;
 }
 
-
-int object_conf_reload(ConfigFile *file, ServerConfiguration *cfg) {
-    HTTPObjectConfig *old_conf = file->data;
-    file->data = load_obj_conf(file->file.ptr);
-    if(old_conf) {
-        object_conf_unref(old_conf);
+int cfg_handle_dav(ServerConfiguration *cfg, ConfigNode *obj) {
+    UcxList *backends = NULL; // list of ConfigArg*
+    UcxAllocator a = util_pool_allocator(cfg->pool);
+    int init_error;
+    
+    // parse args
+    char *uri = NULL;
+    char *ppath = NULL;
+    char *name = NULL;
+    UCX_FOREACH(elm, obj->args) {
+        ConfigArg *arg = elm->data;
+        if(arg->name.ptr == NULL) {
+            // default: uri
+            uri = arg->value.ptr;
+        } else if(!sstrcasecmp(arg->name, SC("uri"))) {
+            uri = arg->value.ptr;
+        } else if(!sstrcasecmp(arg->name, SC("ppath"))) {
+            ppath = arg->value.ptr;
+        } else if(!sstrcasecmp(arg->name, SC("name"))) {
+            name = arg->value.ptr;
+        }
     }
-    if(file->data) {
-        return 0;
-    } else {
+    if(!uri && !ppath && !name) {
         return 1;
     }
-}
-
-void object_conf_ref(HTTPObjectConfig *conf) {
-    if(conf) {
-        ws_atomic_inc32(&conf->ref);
+    
+    // get a list of all DavBackends
+    UCX_FOREACH(elm, obj->children) {
+        ConfigNode *node = elm->data;
+        if(!sstrcasecmp(node->name, SC("DavBackend"))) {
+            if(node->type == CONFIG_NODE_DIRECTIVE) {
+                if(ucx_list_size(node->args) == 1) {
+                    ConfigArg *arg = node->args->data;
+                    backends = ucx_list_append(backends, arg);
+                } else {
+                    log_ereport(LOG_MISCONFIG, "DavBackend must have only one value");
+                    ucx_list_free(backends);
+                    return 1;
+                }
+            } else {
+                log_ereport(LOG_MISCONFIG, "DavBackend must be a directive");
+                ucx_list_free(backends);
+                return 1;
+            }
+        }
     }
+    
+    int ret = 0;
+    WebdavRepository *repository = pool_malloc(cfg->pool, sizeof(WebdavRepository));
+    repository->vfs = NULL;
+    repository->vfsInitData = NULL;
+    repository->davBackends = NULL;
+    
+    // initialize backends
+    UCX_FOREACH(elm, backends) {
+        // the DavBackend value should contain the dav class name
+        ConfigArg *backendArg = elm->data;
+        
+        WebdavType *dav = webdav_get_type((scstr_t){backendArg->value.ptr, backendArg->value.length});
+        if(!dav) {
+            log_ereport(LOG_MISCONFIG, "Unknown webdav backend type '%s'", backendArg->value.ptr);
+            ret = 1;
+            break;
+        }
+        
+        // call backend init
+        // init_data can be NULL, errors will be indicated by init_error
+        void *init_data = webdav_init_backend(cfg, cfg->pool, dav, obj, &init_error);
+        if(init_error) {
+            log_ereport(LOG_FAILURE, "Failed to initialize webdav backend %s", backendArg->value.ptr);
+            ret = 1;
+            break;
+        }
+        
+        WebdavBackendInitData *davInit = pool_malloc(cfg->pool, sizeof(WebdavBackendInitData));
+        if(!davInit) {
+            log_ereport(LOG_FAILURE, "Failed to initialize webdav backend %s: OOM", backendArg->value.ptr);
+            ret = 1;
+            break;
+        }
+        davInit->davType = dav;
+        davInit->davInitData = init_data;
+        
+        repository->davBackends = ucx_list_append_a(&a, repository->davBackends, davInit);
+    }
+    
+    // initialize vfs
+    scstr_t vfs_class = serverconfig_directive_value(obj, SC("VFS"));
+    if(vfs_class.length > 0) {
+        VfsType *vfs = vfs_get_type((scstr_t){vfs_class.ptr, vfs_class.length});
+        if(vfs) {
+            repository->vfs = vfs;
+            repository->vfsInitData = vfs_init_backend(cfg, cfg->pool, vfs, obj, &init_error);
+            ret = init_error;
+        } else {
+            log_ereport(LOG_FAILURE, "Unknown vfs type '%s'", vfs_class.ptr);
+            ret = 1;
+        }
+    }
+    
+    scstr_t object = serverconfig_directive_value(obj, SC("Object"));
+    if(object.length > 0) {
+        repository->object = sstrdup_a(&a, object);
+        if(repository->object.length != object.length) {
+            // OOM
+            log_ereport(LOG_FAILURE, "Cannot create webdav repository: OOM");
+            ret = 1;
+        }
+    }
+    
+    if(!ret) {
+        if(name) {
+            ucx_map_cstr_put(cfg->dav, name, repository);
+        } else {
+            log_ereport(LOG_FAILURE, "TODO: location based dav repositories not implemented");
+            ret = 1;
+        }
+    }
+    
+    return ret;    
 }
 
-void object_conf_unref(HTTPObjectConfig *conf) {
-    uint32_t ref = ws_atomic_dec32(&conf->ref);
-    if(ref == 0) {
-        printf("free HTTPObjectConfig %"PRIxPTR"\n", (intptr_t)conf);
-        pool_destroy(conf->pool);
-    }
-}
-
-HTTPObjectConfig* load_obj_conf(char *file) {
-    log_ereport(LOG_VERBOSE, "load_obj_conf");
-
-    // new conf function test
-    ObjectConfig *cfg = load_object_config(file);
-    UcxAllocator *mp = cfg->parser.mp;
-    if(cfg == NULL) {
-        return NULL;
-    }
-
-    // create object config
-    pool_handle_t *pool = pool_create();
-    HTTPObjectConfig *conf = pool_calloc(pool, sizeof(HTTPObjectConfig), 1);
-    conf->pool = pool;
-
-    // convert ObjectConfig to HTTPObjectConfig
-
-    // add objects
-    conf->nobj = ucx_list_size(cfg->objects);
-    conf->objects = pool_calloc(pool, conf->nobj, sizeof(httpd_object*));
+static int convert_objconf(ServerConfiguration *scfg, ObjectConfig *cfg, HTTPObjectConfig *conf, sstr_t file) {
+    pool_handle_t *pool = conf->pool;
     
     UcxList *objlist = cfg->objects;
     int i = 0;
@@ -772,13 +817,16 @@
         char *ppath = NULL;
         if(cob->name.length > 0) {
             name = sstrdup_pool(pool, cob->name).ptr;
+            if(!name) return -1;
         }
         if(cob->ppath.length > 0) {
             ppath = sstrdup_pool(pool, cob->ppath).ptr;
+            if(!ppath) return -1;
         }
 
         // create and add object
         httpd_object *obj = object_new(pool, name);
+        if(!obj) return -1;
         obj->path = NULL;
 
         conf->objects[i] = obj;
@@ -788,8 +836,9 @@
             UcxList *dirs = cob->directives[j];
             while(dirs != NULL) {
                 ConfigDirective *cfgdir = dirs->data;
-                
+
                 directive *d = pool_malloc(pool, sizeof(directive));
+                if(!d) return -1;
                 if(cfgdir->condition) {
                     sstr_t expr = cfgdir->condition->param_str;
                     d->cond = condition_from_str(pool, expr.ptr, expr.length);
@@ -799,7 +848,7 @@
                 d->param = pblock_create_pool(pool, 8);
 
                 // add params
-                UcxList *param = cfg_param_list(cfgdir->value, mp);
+                UcxList *param = cfg_param_list(cfgdir->value, scfg->a);
                 while(param != NULL) {
                     ConfigParam *p = param->data;
                     pblock_nvlinsert(
@@ -814,13 +863,13 @@
                 // get function
                 char *func_name = pblock_findval("fn", d->param);
                 if(!func_name) {
-                    log_ereport(LOG_MISCONFIG, "%s: Missing fn parameter", file);
-                    return NULL;
+                    log_ereport(LOG_MISCONFIG, "%s: Missing fn parameter", file.ptr);
+                    return -1;
                 }
                 d->func = get_function(func_name);
                 if(!d->func) {
                     log_ereport(LOG_MISCONFIG, "func %s not found", func_name);
-                    return NULL;
+                    return -1;
                 }
 
                 dirs = dirs->next;
@@ -834,66 +883,94 @@
         i++;
         objlist = objlist->next;
     }
+    
+    return 0;
+}
+
+HTTPObjectConfig* objconf_load(ServerConfiguration *scfg, sstr_t file) {
+    log_ereport(LOG_VERBOSE, "load_obj_conf");
+    
+    int ret = 0;
+
+    // create object config
+    pool_handle_t *pool = scfg->pool;
+    HTTPObjectConfig *conf = pool_calloc(pool, sizeof(HTTPObjectConfig), 1);
+    if(!conf) {
+        return NULL;
+    }
+    conf->pool = pool;
+    
+    // load obj config file
+    ObjectConfig *cfg = load_object_config(file.ptr);
+    if(!cfg) {
+        return NULL;
+    }
+
+    // convert ObjectConfig to HTTPObjectConfig
+
+    // add objects
+    conf->nobj = ucx_list_size(cfg->objects);
+    conf->objects = pool_calloc(pool, conf->nobj, sizeof(httpd_object*));
+    if(conf->objects) {
+        ret = convert_objconf(scfg, cfg, conf, file);
+    } else {
+        ret = -1;
+    }
 
     free_object_config(cfg);
 
-    return conf;
+    return !ret ? conf : NULL;
 }
 
-int mime_conf_reload(ConfigFile *file, ServerConfiguration *cfg) {
-    MimeConfig *mimecfg = load_mime_config(file->file.ptr);
-    MimeMap *old_conf = file->data;
-    
-    MimeMap *mimemap = malloc(sizeof(MimeMap));
-    mimemap->ref = 1;
-    UcxMap *map = ucx_map_new((mimecfg->ntypes * 3) / 2);
-    mimemap->map = map;
-    
-    // add ext type pairs
-    UCX_FOREACH(md, mimecfg->directives) {
-        MimeDirective *d = md->data;
-        // add the type for each extension to the map
-        UCX_FOREACH(xl, d->exts) {
-            sstr_t ext = sstr(xl->data);
-            sstr_t value = sstrdup(d->type);
-            ucx_map_sstr_put(map, ext, value.ptr);
-        }
+int mime_conf_load(ServerConfiguration *cfg, sstr_t file) {
+    MimeConfig *mimecfg = load_mime_config(file.ptr);
+    if(!mimecfg) {
+        return -1;
     }
     
-    file->data = mimemap;
+    int ret = 0;
+    
+    // cleanup in case of errors is done by the allocator
+    MimeMap *mimemap = almalloc(cfg->a, sizeof(MimeMap));
+    UcxMap *map = ucx_map_new_a(cfg->a, (mimecfg->ntypes * 3) / 2);
     
-    if(old_conf) {
-        mime_conf_unref(old_conf);
+    if(mimemap && map) {
+        mimemap->map = map;
+        
+        // add ext type pairs
+        UCX_FOREACH(md, mimecfg->directives) {
+            MimeDirective *d = md->data;
+            // add the type for each extension to the map
+            UCX_FOREACH(xl, d->exts) {
+                sstr_t ext = sstr(xl->data);
+                sstr_t value = sstrdup(d->type);
+                if(ucx_map_sstr_put(map, ext, value.ptr)) {
+                    ret = -1;
+                    break;
+                }
+            }
+            if(ret) {
+                break;
+            }
+        }
+        
+        cfg->mimetypes = mimemap;
+    } else {
+        ret = -1;
     }
     
     free_mime_config(mimecfg);
-    return 0;
-}
-
-void mime_conf_ref(MimeMap *conf) {
-    if(conf) {
-        ws_atomic_inc32(&conf->ref);
-    }
+    return ret;
 }
 
-void mime_conf_unref(MimeMap *conf) {
-    uint32_t ref = ws_atomic_dec32(&conf->ref);
-    if(ref == 0) {
-        printf("free MimeConfig %"PRIxPTR"\n", (intptr_t)conf);
-        UcxMapIterator i = ucx_map_iterator(conf->map);
-        char *str;
-        UCX_MAP_FOREACH(key, str, i) {
-            free(str);
-        }
-        ucx_map_free(conf->map);
-        free(conf);
-    }
-}
+
 
-int acl_conf_reload(ConfigFile *file, ServerConfiguration *cfg) {
-    ACLFile *aclfile = load_acl_file(file->file.ptr);
+ACLData* acl_conf_load(ServerConfiguration *cfg, sstr_t file) {
+    ACLFile *aclfile = load_acl_file(file.ptr);
     
-    ACLData *acldata = acl_data_new();
+    // TODO: malloc return checks
+    
+    ACLData *acldata = acl_data_new(cfg->a);
     UCX_FOREACH(elm, aclfile->namedACLs) {
         ACLConfig *ac = elm->data;
         ACLList *acl = acl_config_convert(cfg, ac);
@@ -902,17 +979,13 @@
     }
     free_acl_file(aclfile);
     
-    ACLData *old_data = file->data;
-    file->data = acldata;
-    if(old_data) {
-        acl_data_unref(old_data);
-    }
-    
-    return 0;
+    return acldata;
 }
 
 ACLList* acl_config_convert(ServerConfiguration *cfg, ACLConfig *acl) {
-    WSAcl *acllist = malloc(sizeof(WSAcl));
+    UcxAllocator *a = cfg->a;
+    
+    WSAcl *acllist = almalloc(cfg->a, sizeof(WSAcl));
     acllist->acl.check = (acl_check_f)wsacl_check;
     acllist->acl.authdb = NULL;
     acllist->acl.authprompt = NULL;
@@ -925,8 +998,8 @@
     }
     
     size_t s = ucx_list_size(acl->entries);
-    WSAce **aces = calloc(s, sizeof(WSAce*));
-    WSAce **eces = calloc(s, sizeof(WSAce*));
+    WSAce **tmp_aces = calloc(s, sizeof(WSAce*));
+    WSAce **tmp_eces = calloc(s, sizeof(WSAce*));
     int ai = 0;
     int ei = 0;
     
@@ -935,36 +1008,36 @@
         ACEConfig *acecfg = elm->data;
         
         // copy data
-        WSAce *ace = malloc(sizeof(WSAce));
+        WSAce *ace = almalloc(a, sizeof(WSAce));
         ace->access_mask = acecfg->access_mask;
         ace->flags = acecfg->flags;
         ace->type = acecfg->type;
-        ace->who = sstrdup(acecfg->who).ptr;
+        ace->who = sstrdup_a(a, acecfg->who).ptr;
         
         // add the entry to the correct array
         if(ace->type >= ACL_TYPE_AUDIT) {
-            eces[ei] = ace;
+            tmp_eces[ei] = ace;
             ei++;
         } else {
-            aces[ai] = ace;
+            tmp_aces[ai] = ace;
             ai++;
         }
     }
     
     // create new entrie arrays with perfect fitting size
     if(ai > 0) {
-        acllist->ace = calloc(ai, sizeof(WSAce*));
+        acllist->ace = alcalloc(a, ai, sizeof(WSAce*));
     }
     if(ei > 0) {
-        acllist->ece = calloc(ei, sizeof(WSAce*));
+        acllist->ece = alcalloc(a, ei, sizeof(WSAce*));
     }
-    memcpy(acllist->ace, aces, ai*sizeof(WSAce*));
-    memcpy(acllist->ece, eces, ei*sizeof(WSAce*));
+    memcpy(acllist->ace, tmp_aces, ai*sizeof(WSAce*));
+    memcpy(acllist->ece, tmp_eces, ei*sizeof(WSAce*));
     acllist->acenum = ai;
     acllist->ecenum = ei;
     
-    free(aces);
-    free(eces);
+    free(tmp_aces);
+    free(tmp_eces);
     
     // get authentication information
     if(acl->authparam) {
@@ -975,7 +1048,7 @@
             AuthDB *authdb = ucx_map_sstr_get(cfg->authdbs, authdb_str);
             acllist->acl.authdb = authdb;
             if(authdb && prompt_str.ptr) {
-                acllist->acl.authprompt = sstrdup(prompt_str).ptr;
+                acllist->acl.authprompt = sstrdup_a(a, prompt_str).ptr;
             }
         }
     }
@@ -983,69 +1056,47 @@
     return &acllist->acl;
 }
 
-int keyfile_reload(ConfigFile *file, ServerConfiguration *cfg) {
-    KeyfileConfig *conf = load_keyfile_config(file->file.ptr);
-    if(!conf) {
-        return 1;
+AuthDB* keyfile_load(ServerConfiguration *cfg, scstr_t file) {
+    Keyfile *keyfile = keyfile_new(cfg->a);
+    if(!keyfile) {
+        return NULL;
     }
     
-    Keyfile *keyfile = keyfile_new();
+    KeyfileConfig *conf = load_keyfile_config(file.ptr);
+    if(!conf) {
+        return NULL;
+    }
+    
+    AuthDB *ret = &keyfile->authdb;
     
     UCX_FOREACH(elm, conf->users) {
         KeyfileEntry *user = elm->data;
-        keyfile_add_user(
+        if(keyfile_add_user(
                 keyfile,
                 user->name,
                 user->hashtype,
                 user->hashdata,
                 user->groups,
-                user->numgroups);
+                user->numgroups))
+        {
+            ret = NULL;
+            break;
+        }
     }
     
     free_keyfile_config(conf);
     
-    Keyfile *old_data = file->data;
-    file->data = keyfile;
-    if(old_data) {
-        keyfile_unref(old_data);
-    }
-    
-    return 0;
+    return ret;
 }
 
-
-sstr_t cfg_load_file(sstr_t file) {
-    sstr_t r;
-    r.ptr = NULL;
-    r.length = 0;
-    
-    if(!file.ptr) {
-        return r;
-    }
-    
-    sstr_t f = sstrdup(file);
-    FILE *in = fopen(f.ptr, "r");
-    if(!in) {
-        return r;
+pblock* config_obj2pblock(pool_handle_t *pool, ConfigNode *obj) {
+    pblock *pb = pblock_create_pool(pool, 8);
+    UCX_FOREACH(elm, obj->children) {
+        ConfigNode *d = elm->data;
+        if(d->type == CONFIG_NODE_DIRECTIVE && d->name.length > 0 && ucx_list_size(d->args) == 1) {
+            ConfigArg *arg = d->args->data;
+            pblock_nvlinsert(d->name.ptr, d->name.length, arg->value.ptr, arg->value.length, pb);
+        }
     }
-    
-    UcxBuffer *buf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND);
-    if(!buf) {
-        fclose(in);
-        return r;
-    }
-    
-    if(ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write) == 0) {
-        fclose(in);
-        ucx_buffer_free(buf);
-        return r;
-    }
-    
-    r.ptr = buf->space;
-    r.length = buf->pos;
-    
-    free(buf);
-    fclose(in);
-    
-    return r;
+    return pb;
 }

mercurial