dav/sync.c

changeset 747
efbd59642577
parent 739
bba6a6e221b4
child 749
bbadf84cfc2d
--- a/dav/sync.c	Sun Apr 16 14:12:24 2023 +0200
+++ b/dav/sync.c	Fri Apr 21 21:25:32 2023 +0200
@@ -36,9 +36,10 @@
 #include <utime.h>
 #include <libxml/xmlerror.h>
 #include <sys/types.h>
-#include <ucx/string.h>
-#include <ucx/utils.h>
-#include <ucx/properties.h>
+#include <cx/string.h>
+#include <cx/utils.h>
+#include <cx/hash_map.h>
+#include <cx/printf.h>
 #include <dirent.h>
 
 #include <math.h>
@@ -355,12 +356,12 @@
 
 static int res_matches_filter(Filter *filter, char *res_path) {
     // include/exclude filter
-    UCX_FOREACH(inc, filter->include) {
-        regex_t* pattern = (regex_t*) inc->data;
+    CxIterator i = cxListIterator(filter->include);
+    cx_foreach(regex_t*, pattern, i) {
         if (regexec(pattern, res_path, 0, NULL, 0) == 0) {
-            UCX_FOREACH(exc, filter->exclude) {
-                regex_t* pattern = (regex_t*) exc->data;
-                if (regexec(pattern, res_path, 0, NULL, 0) == 0) {
+            CxIterator e = cxListIterator(filter->exclude);
+            cx_foreach(regex_t*, expat, e) {
+                if (regexec(expat, res_path, 0, NULL, 0) == 0) {
                     return 1;
                 }
             }
@@ -373,7 +374,7 @@
 static int res_matches_dir_filter(SyncDirectory *dir, char *res_path) {
     // trash filter
     if (dir->trash) {
-        sstr_t rpath = sstr(util_concat_path(dir->path, res_path));
+        cxmutstr rpath = cx_mutstr(util_concat_path(dir->path, res_path));
         if (util_path_isrelated(dir->trash, rpath.ptr)) {
             free(rpath.ptr);
             return 1;
@@ -407,12 +408,11 @@
     }
     
     DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_PROPS_NS, "tags");
-    UcxList *res_tags = parse_dav_xml_taglist(tagsprop);
+    CxList *res_tags = parse_dav_xml_taglist(tagsprop);
     
     int ret = matches_tagfilter(res_tags, tagfilter);
     
-    ucx_list_free_content(res_tags, (ucx_destructor) free_dav_tag);
-    ucx_list_free(res_tags);
+    cxListDestroy(res_tags);
     
     return ret;
 }
@@ -436,14 +436,11 @@
     }
 
     DavBool changed = 0;
-    UcxList *res_tags = sync_get_file_tags(dir, res, &changed, NULL);
+    CxList *res_tags = sync_get_file_tags(dir, res, &changed, NULL);
     
     int ret = matches_tagfilter(res_tags, tagfilter);
-    UCX_FOREACH(elm, res_tags) {
-        DavTag *t = elm->data;
-        free_dav_tag(t);
-    }
-    ucx_list_free(res_tags);
+    CxIterator i = cxListIterator(res_tags);
+    cxListDestroy(res_tags);
     return ret;
 }
 
@@ -510,7 +507,7 @@
 }
 
 static void localres_keep(SyncDatabase *db, const char *path) {
-    LocalResource *local = ucx_map_cstr_remove(db->resources, path);
+    LocalResource *local = cxMapRemoveAndGet(db->resources, cx_hash_key_str(path));
     if(local) {
         local->keep = TRUE;
     }
@@ -528,21 +525,23 @@
     return 1;
 }
 
-void res2map(DavResource *root, UcxMap *map) {
-    UcxList *stack = ucx_list_prepend(NULL, root->children);
-    while(stack) {
-        DavResource *res = stack->data;
-        stack = ucx_list_remove(stack, stack);
+void res2map(DavResource *root, CxMap *map) {
+    CxList *stack = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    cxListInsert(stack, 0, root->children);
+    while(stack->size > 0) {
+        DavResource *res = cxListAt(stack, 0);
+        cxListRemove(stack, 0);
         
         while(res) {
-            ucx_map_cstr_put(map, res->path, res);
+            cxMapPut(map, cx_hash_key_str(res->path), res);
             
             if(res->children) {
-                stack = ucx_list_prepend(stack, res->children);
+                cxListInsert(stack, 0, res->children);
             }
             res = res->next;
         }
     }
+    cxListDestroy(stack);
 }
 
 int cmd_pull(CmdArgs *a, DavBool incoming) {
@@ -575,7 +574,7 @@
         return -1;
     }
     
-    Repository *repo = get_repository(sstr(dir->repository));
+    Repository *repo = get_repository(cx_str(dir->repository));
     if(!repo) {
         fprintf(stderr, "Unknown repository %s\n", dir->repository);
         return -1;
@@ -588,13 +587,13 @@
     }
     remove_deleted_conflicts(dir, db);
     
-    UcxMap *hashes = NULL;
+    CxMap *hashes = NULL;
     if(SYNC_HASHING(dir)) {
         hashes = create_hash_index(db);
     }
     
     DavSession *sn = create_session(a, ctx, repo, dir->collection);
-    ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db);
+    util_regdestr(sn->mp, db, (cx_destructor_func)destroy_db);
     if (cmd_getoption(a, "verbose")) {
         curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L);
         curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr);
@@ -664,31 +663,32 @@
     int sync_error = 0;
     int sync_conflict = 0;
     
-    UcxList *res_modified = NULL;
-    UcxList *res_new = NULL;
-    UcxList *res_moved = NULL; // type: MovedFile
-    UcxList *res_link = NULL;
-    UcxList *res_conflict = NULL;
-    UcxList *res_mkdir = NULL;
-    UcxList *res_metadata = NULL;
-    UcxList *res_broken = NULL;
-    UcxMap  *lres_removed = ucx_map_new(16); // type: LocalResource*
+    CxList *res_modified = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    CxList *res_new = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    CxList *res_moved = cxLinkedListCreateSimple(CX_STORE_POINTERS); // type: MovedFile
+    CxList *res_link = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    CxList *res_conflict = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    CxList *res_mkdir = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    CxList *res_metadata = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    CxList *res_broken = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    CxMap  *lres_removed = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); // type: LocalResource*
     
     //UcxMap *svrres = ucx_map_new(db->resources->count);
-    UcxMap *dbres = ucx_map_clone(db->resources, NULL, NULL);
-    
-    UcxList *stack = ucx_list_prepend(NULL, ls->children);
-    while(stack) {
-        DavResource *res = stack->data;
-        stack = ucx_list_remove(stack, stack);
+    CxMap *dbres = NULL; // TODO: ucx_map_clone(db->resources, NULL, NULL);
+    
+    CxList *stack = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    cxListInsert(stack, 0, ls->children);
+    while(stack->size > 0) {
+        DavResource *res = cxListAt(stack, 0);
+        cxListRemove(stack, 0);
          
         while(res) {
             DavBool res_filtered = FALSE;
             if (res_matches_dir_filter(dir, res->path)) {
                 res_filtered = TRUE;
             } else {
-                UCX_FOREACH(elm, dir->filter.tags) {
-                    SyncTagFilter *tf = elm->data;
+                CxIterator iter = cxListIterator(dir->filter.tags);
+                cx_foreach(SyncTagFilter *, tf, iter) {
                     if(!res_matches_tags(res, tf)) {
                         res_filtered = TRUE;
                         break;
@@ -714,7 +714,7 @@
             if(status && !strcmp(status, "broken")) {
                 res = res->next;
                 localres_keep(db, res->path);
-                res_broken = ucx_list_append(res_broken, res);
+                cxListAdd(res_broken, res);
                 continue;
             }
             
@@ -723,28 +723,28 @@
             switch(change) {
                 case REMOTE_NO_CHANGE: break;
                 case REMOTE_CHANGE_MODIFIED: {
-                    res_modified = ucx_list_append(res_modified, res);
+                    cxListAdd(res_modified, res);
                     break;
                 }
                 case REMOTE_CHANGE_NEW: {
-                    res_new = ucx_list_append(res_new, res);
+                    cxListAdd(res_new, res);
                     break;
                 }
                 case REMOTE_CHANGE_DELETED: break; // never happens
                 case REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED: {
-                    res_conflict = ucx_list_append(res_conflict, res);
+                    cxListAdd(res_conflict, res);
                     break;
                 }
                 case REMOTE_CHANGE_METADATA: {
-                    res_metadata = ucx_list_append(res_metadata, res);
+                    cxListAdd(res_metadata, res);
                     break;
                 }
                 case REMOTE_CHANGE_MKDIR: {
-                    res_mkdir = ucx_list_append(res_mkdir, res);
+                    cxListAdd(res_mkdir, res);
                     break;
                 }
                 case REMOTE_CHANGE_LINK: {
-                    res_link = ucx_list_append(res_link, res);
+                    cxListAdd(res_link, res);
                     break;
                 }
             }
@@ -752,10 +752,10 @@
             // remove every server resource from dbres
             // all remaining elements are the resources that are removed
             // on the server
-            ucx_map_cstr_remove(dbres, res->path);
+            cxMapRemove(dbres, cx_hash_key_str(res->path));
             
             if(!dav_get_property_ns(res, DAV_NS, "split") && res->children) {
-                stack = ucx_list_prepend(stack, res->children);
+                cxListInsert(stack, 0, res->children);
             }
             res = res->next;
         }
@@ -764,16 +764,15 @@
     // find deleted resources
     // svrres currently contains all resources from the server
     // and will replace the current db->resources map later
-    UcxMapIterator i = ucx_map_iterator(dbres);
-    LocalResource *local;
-    UCX_MAP_FOREACH(key, local, i) {
+    CxIterator i = cxMapIteratorValues(dbres);
+    cx_foreach(LocalResource *, local, i) {
         if (res_matches_dir_filter(dir, local->path)) {
             continue;
         }
         if(!local->keep) {
-            ucx_map_cstr_put(lres_removed, local->path, local);
-            if(lres_removed->count > lres_removed->size * 2) {
-                ucx_map_rehash(lres_removed);
+            cxMapPut(lres_removed, cx_hash_key_str(local->path), local);
+            if(lres_removed->size > lres_removed->size * 2) {
+                cxMapRehash(lres_removed);
             }
         }
     }
@@ -783,31 +782,25 @@
     //
     
     // the first thing we need are all directories to put the files in
-    UCX_FOREACH(elm, res_mkdir) {
-        DavResource *res = elm->data;
+    i = cxListIterator(res_mkdir);
+    cx_foreach(DavResource *, res, i) {
         if(sync_get_collection(a, dir, res, db)) {
             sync_error++;
         }
     }
     
     // we need a map for all conflicts for fast lookups
-    UcxMap *conflicts = ucx_map_new(ucx_list_size(res_conflict)+16);
-    UCX_FOREACH(elm, res_conflict) {
-        DavResource *res = elm->data;
-        ucx_map_cstr_put(conflicts, res->path, res);
+    CxMap *conflicts = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, res_conflict->size+16);
+    i = cxListIterator(res_conflict);
+    cx_foreach(DavResource *, res, i) {
+        cxMapPut(conflicts, cx_hash_key_str(res->path), res);
     }
     
     if(SYNC_HASHING(dir)) {
         // check for moved/copied files
-        UcxList *elm = res_new;
-        UcxList *prev = NULL;
-        UcxList *next = NULL;
         SYS_STAT s;
-        for(;elm;elm=next) {
-            DavResource *res = elm->data;
-            prev = elm->prev;
-            next = elm->next;
-            
+        CxMutIterator mut_iter = cxListMutIterator(res_new);
+        cx_foreach(DavResource *, res, mut_iter) {
             if(dav_get_property_ns(res, DAV_PROPS_NS, "link")) {
                 continue;
             }
@@ -817,7 +810,7 @@
                 continue;
             }
             
-            LocalResource *local = ucx_map_cstr_get(hashes, hash);
+            LocalResource *local = cxMapGet(hashes, cx_hash_key_str(hash));
             if(!local) {
                 continue;
             }
@@ -833,35 +826,28 @@
             MovedFile *mf = malloc(sizeof(MovedFile));
             mf->content = local;
             mf->resource = res;
-            if(ucx_map_cstr_remove(lres_removed, local->path)) {
+            if(cxMapRemoveAndGet(lres_removed, cx_hash_key_str(local->path))) {
                 mf->copy = FALSE;
             } else {
                 mf->copy = TRUE;
             }
             
-            res_moved = ucx_list_append(res_moved, mf);
+            cxListAdd(res_moved, mf);
             
             // remove item from res_new
-            if(prev) {
-                prev->next = next;
-            } else {
-                res_new = next;
-            }
-            if(next) {
-                next->prev = prev;
-            }
+            cxIteratorFlagRemoval(mut_iter);
         }
     }
     
     // do copy/move operations
-    UCX_FOREACH(elm, res_moved) {
-        MovedFile *mf = elm->data;
+    i = cxListIterator(res_moved);
+    cx_foreach(MovedFile *, mf, i) {
         if(sync_shutdown) {
             break;
         }
         
         DavBool issplit = dav_get_property_ns(mf->resource, DAV_NS, "split") ? 1 : 0;  
-        if(ucx_map_cstr_get(conflicts, mf->resource->path)) {
+        if(cxMapGet(conflicts, cx_hash_key_str(mf->resource->path))) {
             rename_conflict_file(dir, db, mf->resource->path, issplit);
             sync_conflict++;
         }
@@ -874,36 +860,45 @@
     }
     
     // download all new, modified and conflict files
-    UcxList *download = ucx_list_concat(res_modified, res_conflict);
-    download = ucx_list_concat(res_new, download);
-    download = ucx_list_concat(download, res_link);
-    UCX_FOREACH(elm, download) {
-        DavResource *res = elm->data;
+    for(int n=0;n<4;n++) {
+        CxList *ls;
+        if(n == 0) {
+            ls = res_new;
+        } else if(n == 1) {
+            ls = res_modified;
+        } else if(n == 2) {
+            ls = res_conflict;
+        } else {
+            ls = res_link;
+        }
+        CxIterator iter = cxListIterator(ls);
+        cx_foreach(DavResource *, res, iter) {
+            if(sync_shutdown) {
+                break;
+            }
+            
+            DavBool issplit = dav_get_property_ns(res, DAV_NS, "split") ? 1 : 0;  
+            if(cxMapGet(conflicts, cx_hash_key_str(res->path))) {
+                rename_conflict_file(dir, db, res->path, issplit);
+                sync_conflict++;
+            }
+
+            // download the resource
+            if(sync_get_resource(a, dir, res->path, res, db, TRUE, &sync_success)) {
+                fprintf(stderr, "resource download failed: %s\n", res->path);
+                sync_error++;
+            }
+        }
+    }
+    
+    // update metadata
+    i = cxListIterator(res_metadata);
+    cx_foreach(DavResource *, res, i) {
         if(sync_shutdown) {
             break;
         }
         
-        DavBool issplit = dav_get_property_ns(res, DAV_NS, "split") ? 1 : 0;  
-        if(ucx_map_cstr_get(conflicts, res->path)) {
-            rename_conflict_file(dir, db, res->path, issplit);
-            sync_conflict++;
-        }
-        
-        // download the resource
-        if(sync_get_resource(a, dir, res->path, res, db, TRUE, &sync_success)) {
-            fprintf(stderr, "resource download failed: %s\n", res->path);
-            sync_error++;
-        }
-    }
-    
-    // update metadata
-    UCX_FOREACH(elm, res_metadata) {
-        DavResource *res = elm->data;
-        if(sync_shutdown) {
-            break;
-        }
-        
-        LocalResource *local = ucx_map_cstr_get(db->resources, res->path);
+        LocalResource *local = cxMapGet(db->resources, cx_hash_key_str(res->path));
         if(local) {
             printf("update: %s\n", res->path);
             char *res_path = resource_local_path(res);
@@ -929,36 +924,35 @@
         }
     }
     
-    UcxList *rmdirs = NULL;
-    UcxMapIterator mi = ucx_map_iterator(lres_removed);
+    CxList *rmdirs = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_pathlen_cmp, CX_STORE_POINTERS);
+    i = cxMapIteratorValues(lres_removed);
     LocalResource *removed_res;
-    UcxKey key;
-    UCX_MAP_FOREACH(key, removed_res, mi) {
+    cx_foreach(LocalResource *, removed_res, i) {
         if(sync_shutdown) {
             break;
         }
         
         int ret = sync_remove_local_resource(dir, removed_res);
         if(ret == -1) {
-            rmdirs = ucx_list_append(rmdirs, removed_res);
+            cxListAdd(rmdirs, removed_res);
         } else if(ret == 0) {
-            LocalResource *local = ucx_map_cstr_remove(db->resources, removed_res->path);
+            LocalResource *local = cxMapRemoveAndGet(db->resources, cx_hash_key_str(removed_res->path));
             if(local) {
                 local_resource_free(local);
             }
             sync_delete++;
         }     
     }
-    ucx_map_free(lres_removed);
+    cxMapDestroy(lres_removed);
     
     // sort dir list, we need to delete dirs with higher depth first
-    rmdirs = ucx_list_sort(rmdirs, (cmp_func)resource_pathlen_cmp, NULL);
+    cxListSort(rmdirs);
     // delete dirs
-    UCX_FOREACH(elm, rmdirs) {
-        LocalResource *local_dir = elm->data;
+    i = cxListIterator(rmdirs);
+    cx_foreach(LocalResource *, local_dir, i) {
         if(!sync_remove_local_directory(dir, local_dir)) {
             // dir successfully removed, now remove the related db entry
-            LocalResource *local = ucx_map_cstr_remove(db->resources, local_dir->path);
+            LocalResource *local = cxMapRemoveAndGet(db->resources, cx_hash_key_str(local_dir->path));
             if(local) {
                 local_resource_free(local);
             }
@@ -1030,7 +1024,7 @@
     RemoteChangeType type = cmd_getoption(a, "conflict") ?
             REMOTE_CHANGE_MODIFIED : REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED;
     
-    LocalResource *local = ucx_map_cstr_get(db->resources, res->path);
+    LocalResource *local = cxMapGet(db->resources, cx_hash_key_str(res->path));
     char *local_path = create_local_path(dir, res->path);
     
     char *link = SYNC_SYMLINK(dir) ? 
@@ -1081,9 +1075,9 @@
                 nochange = TRUE;
             }
         } else if(local->etag) {
-            sstr_t e = sstr(etag);
-            if(sstrprefix(e, S("W/"))) {
-                e = sstrsubs(e, 2);
+            cxstring e = cx_str(etag);
+            if(cx_strprefix(e, CX_STR("W/"))) {
+                e = cx_strsubs(e, 2);
             }
             if(!strcmp(e.ptr, local->etag)) {
                 // resource is already up-to-date on the client
@@ -1164,7 +1158,7 @@
         // check if tags have changed
         if(dir->tagconfig) {
             DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_PROPS_NS, "tags");
-            UcxList *remote_tags = NULL;
+            CxList *remote_tags = NULL;
             if(tagsprop) {
                 remote_tags = parse_dav_xml_taglist(tagsprop);
             }
@@ -1213,7 +1207,7 @@
             local = calloc(1, sizeof(LocalResource));
             local->path = strdup(res->path);
             
-            ucx_map_cstr_put(db->resources, local->path, local);
+            cxMapPut(db->resources, cx_hash_key_str(local->path), local);
         }
         
         // update local res
@@ -1245,7 +1239,7 @@
     local->size = s->st_size;
 }
 
-static UcxList* sync_download_changed_parts(
+static CxList* sync_download_changed_parts(
         DavResource *res,
         LocalResource *local,
         FILE *out,
@@ -1254,7 +1248,8 @@
         int64_t *truncate_file,
         int *err)
 {
-    UcxList *updates = NULL;
+    CxList *updates = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    updates->simple_destructor = (cx_destructor_func)filepart_free;
     
     size_t local_numparts = local ? local->numparts : 0;
     fseeko(out, 0, SEEK_END);
@@ -1262,7 +1257,7 @@
     
     int error = 0;
     
-    UcxBuffer *buf = ucx_buffer_new(NULL, blocksize, 0);
+    CxBuffer *buf = cxBufferCreate(NULL, blocksize, cxDefaultAllocator, 0);
     
     int64_t maxsize = -1;
     
@@ -1306,7 +1301,7 @@
                 }
                 buf->pos = 0;
                 buf->size = 0;
-                if(dav_get_content(part, buf,(dav_write_func)ucx_buffer_write)) {
+                if(dav_get_content(part, buf,(dav_write_func)cxBufferWrite)) {
                     fprintf(stderr, "Error: cannot download part: %s\n", part->name);
                     error = 1;
                     break;
@@ -1321,7 +1316,7 @@
                 update->block = partnum;
                 update->etag = etag ? strdup(etag) : NULL;
                 update->hash = dav_create_hash(buf->space, buf->size);
-                updates = ucx_list_append(updates, update);
+                cxListAdd(updates, update);
                 
                 block_end = offset+buf->size;
             } else {
@@ -1343,11 +1338,11 @@
         part = part->next;
     }
     
-    ucx_buffer_free(buf);
+    cxBufferFree(buf);
     
     if(error) {
         *err = 1;
-        ucx_list_free_content(updates, (ucx_destructor)filepart_free);
+        cxListDestroy(updates);
         return NULL;
     }
     
@@ -1373,7 +1368,7 @@
         return 1;
     }
     
-    ucx_stream_copy(in, out, (read_func)fread, (write_func)fwrite);
+    cx_stream_copy(in, out, (cx_read_func)fread, (cx_write_func)fwrite);
     fclose(in);
     fclose(out);
     
@@ -1415,7 +1410,7 @@
     } else {
         // reuse previous LocalResource (content)
         // remove it from db->resources, change path and put it back
-        local = ucx_map_cstr_remove(db->resources, content->path);
+        local = cxMapRemoveAndGet(db->resources, cx_hash_key_str(content->path));
         if(!local) {
             // can't happen, but handle it nevertheless
             local = content;
@@ -1423,7 +1418,7 @@
         free(content->path);
         local->path = strdup(res->path);
     }
-    ucx_map_cstr_put(db->resources, local->path, local);
+    cxMapPut(db->resources, cx_hash_key_str(local->path), local);
     
     if(sync_store_metadata(dir, new_path, local, res)) {
         fprintf(stderr, "Cannot store metadata: %s\n", res->path);
@@ -1463,7 +1458,7 @@
     char *link = SYNC_SYMLINK(dir) ?
             dav_get_string_property_ns(res, DAV_PROPS_NS, "link") : NULL;
     
-    LocalResource *local = ucx_map_cstr_get(db->resources, path);
+    LocalResource *local = cxMapGet(db->resources, cx_hash_key_str(path));
     
     char *local_path;
     if(link) {
@@ -1488,7 +1483,7 @@
         }
         issplit = TRUE;
     }
-    UcxList *part_updates = NULL;
+    CxList *part_updates = NULL;
     uint64_t blockcount = 0;
     char *content_hash = NULL;
        
@@ -1590,7 +1585,7 @@
             // new local resource
             local = calloc(1, sizeof(LocalResource));
             local->path = strdup(path);
-            ucx_map_cstr_put(db->resources, local->path, local);
+            cxMapPut(db->resources, cx_hash_key_str(local->path), local);
         }
         
         if(sync_store_metadata(dir, local_path, local, res)) {
@@ -1673,11 +1668,11 @@
     }
       
     // if it doesn't exist in the db, create an entry for the dir
-    LocalResource *local = ucx_map_cstr_get(db->resources, res->path);
+    LocalResource *local = cxMapGet(db->resources, cx_hash_key_str(res->path));
     if(!local) {
         local = calloc(1, sizeof(LocalResource));
         local->path = strdup(res->path);
-        ucx_map_cstr_put(db->resources, local->path, local);
+        cxMapPut(db->resources, cx_hash_key_str(local->path), local);
     }
     local->isdirectory = 1;
     
@@ -1770,14 +1765,14 @@
     int loop = 1;
     do {
         char *res_parent = util_parent_path(path);
-        char *res_name = util_resource_name(path);
+        const char *res_name = util_resource_name(path);
         
-        sstr_t new_path = ucx_sprintf(
+        cxmutstr new_path = cx_asprintf(
             "%sorig.%d.%s",
             parent,
             rev,
             res_name);
-        sstr_t new_res_path = ucx_sprintf(
+        cxmutstr new_res_path = cx_asprintf(
             "%sorig.%d.%s",
             res_parent,
             rev,
@@ -1799,7 +1794,7 @@
                     LocalResource *conflict = calloc(1, sizeof(LocalResource));
                     conflict->path = strdup(new_res_path.ptr);
                     conflict->conflict_source = strdup(path);
-                    ucx_map_cstr_put(db->conflict, new_res_path.ptr, conflict);
+                    cxMapPut(db->conflict, cx_hash_key_str(new_res_path.ptr), conflict);
                 }
             }
         }
@@ -1817,8 +1812,7 @@
     char *new_path = NULL;
     char *parent = util_parent_path(path);
     for (int i=0;;i++) {
-        sstr_t np = ucx_asprintf(
-        ucx_default_allocator(),
+        cxmutstr np = cx_asprintf(
             "%sdownload%d-%s",
             parent,
             i,
@@ -1841,8 +1835,7 @@
 void move_to_trash(SyncDirectory *dir, char *path) {
     char *new_path = NULL;
     for (int i=0;;i++) {
-        sstr_t np = ucx_asprintf(
-        ucx_default_allocator(),
+        cxmutstr np = cx_asprintf(
             "%s%d-%s",
             dir->trash,
             i,
@@ -1876,7 +1869,7 @@
 }
 
 static int res_isconflict(SyncDatabase *db, LocalResource *res) {
-    return ucx_map_cstr_get(db->conflict, res->path) ? 1 : 0;
+    return cxMapGet(db->conflict, cx_hash_key_str(res->path)) ? 1 : 0;
 }
 
 int cmd_push(CmdArgs *a, DavBool outgoing, DavBool archive) {
@@ -1917,7 +1910,7 @@
         return -1;
     }
     
-    Repository *repo = get_repository(sstr(dir->repository));
+    Repository *repo = get_repository(cx_str(dir->repository));
     if(!repo) {
         fprintf(stderr, "Unkown repository %s\n", dir->name);
         return -1;
@@ -1931,7 +1924,7 @@
     remove_deleted_conflicts(dir, db);
     
     DavSession *sn = create_session(a, ctx, repo, dir->collection);
-    ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db);
+    util_regdestr(sn->mp, db, (cx_destructor_func)destroy_db);
     if (cmd_getoption(a, "verbose")) {
         curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L);
         curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr);
@@ -1953,9 +1946,9 @@
         return -1;
     }
     
-    UcxMap *svrres = NULL;
+    CxMap *svrres = NULL;
     if(restore) {
-        svrres = ucx_map_new(1024);
+        svrres = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 1024);
         res2map(root, svrres);
     }
     
@@ -1981,7 +1974,7 @@
     
     DavBool remove_file = cmd_getoption(a, "remove") ? 1 : 0;
     
-    UcxMap *db_hashes = NULL;
+    CxMap *db_hashes = NULL;
     if(SYNC_HASHING(dir)) {
         db_hashes = create_hash_index(db);
     }
@@ -1991,23 +1984,24 @@
     int sync_conflict = 0;
     int sync_error = 0;
     
-    UcxList *ls_new = NULL;
-    UcxList *ls_modified = NULL;
-    UcxList *ls_conflict = NULL;
-    UcxList *ls_update = NULL;
-    UcxList *ls_delete = NULL;
-    UcxList *ls_move = NULL;
-    UcxList *ls_copy = NULL;
-    UcxList *ls_mkcol = NULL;
+    CxList *ls_new = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
+    CxList *ls_modified = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
+    CxList *ls_conflict = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
+    CxList *ls_update = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
+    CxList *ls_delete = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
+    CxList *ls_move = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
+    CxList *ls_copy = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
+    CxList *ls_mkcol = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
+    
       
     // upload all changed files
     //UcxList *resources = cmd_getoption(a, "read") ?
     //        read_changes(dir, db) : local_scan(dir, db);
-    UcxList *resources = local_scan(dir, db);
-    UcxMap *resources_map = ucx_map_new(ucx_list_size(resources)+16);
-    
-    UCX_FOREACH(elm, resources) {
-        LocalResource *local_res = elm->data;
+    CxList *resources = local_scan(dir, db);
+    CxMap *resources_map = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, resources->size+16);
+    
+    CxIterator iter = cxListIterator(resources);
+    cx_foreach(LocalResource *, local_res, iter) {
         // ignore all files, that are excluded by a static filter (sync.xml) 
         
         // static include/exclude filter
@@ -2015,22 +2009,25 @@
             continue;
         }
         // static tag filter
-        UCX_FOREACH(elm, dir->filter.tags) {
-            SyncTagFilter *tf = elm->data;
-            if(!localres_matches_tags(dir, local_res, tf)) {
-                continue;
+        if(dir->filter.tags) {
+            CxIterator tag_iter = cxListIterator(dir->filter.tags);
+            cx_foreach(SyncTagFilter *, tf, tag_iter) {
+                if(!localres_matches_tags(dir, local_res, tf)) {
+                    continue;
+                }
             }
         }
         
+        
         // we need a fast file lookup map later to detect deleted files
-        ucx_map_cstr_put(resources_map, local_res->path, local_res);
+        cxMapPut(resources_map, cx_hash_key_str(local_res->path), local_res);
         
         // dynamic tag filter
         if(!localres_matches_tags(dir, local_res, tagfilter)) {
             if(!remove_file) {
-                LocalResource *dbres = ucx_map_cstr_get(
+                LocalResource *dbres = cxMapGet(
                         db->resources,
-                        local_res->path);
+                        cx_hash_key_str(local_res->path));
                 if(dbres) {
                     // this makes sure the file will not be deleted later
                     dbres->keep = TRUE;
@@ -2041,7 +2038,7 @@
         
         // skip conflict backups silently
         if(res_isconflict(db, local_res)) {
-            ls_conflict = ucx_list_append(ls_conflict, local_res);
+            cxListAdd(ls_conflict, local_res);
             continue;
         }
         
@@ -2054,14 +2051,14 @@
                     restore_modified);
         if(is_changed) {
             if(local_res->isdirectory) {
-                ls_mkcol = ucx_list_append(ls_mkcol, local_res);
+                cxListAdd(ls_mkcol, local_res);
             } else if(local_res->isnew) {
-                ls_new = ucx_list_append(ls_new, local_res);
+                cxListAdd(ls_new, local_res);
             } else {
-                ls_modified = ucx_list_append(ls_modified, local_res);
+                cxListAdd(ls_modified, local_res);
             }
         } else if(local_res->metadata_updated) {
-            ls_update = ucx_list_append(ls_update, local_res);
+            cxListAdd(ls_update, local_res);
         }
         
         if(local_res->isnew) {
@@ -2077,13 +2074,9 @@
     if(SYNC_STORE_HASH(dir)) {
         // calculate hashes of all new files and check if a file
         // was moved or is a copy
-        UcxList *elm = ls_new;
-        while(elm) {
-            LocalResource *local = elm->data;
-            UcxList *prev = elm->prev;
-            UcxList *next = elm->next;
+        CxMutIterator mut_iter = cxListMutIterator(ls_new);
+        cx_foreach(LocalResource *, local, mut_iter) {
             if(local->isdirectory || local->link_target) {
-                elm = elm->next;
                 continue;
             }
             
@@ -2091,78 +2084,70 @@
             char *hash = util_file_hash(local_path);
             local->hash = hash;
             // check if a file with this hash already exists
-            LocalResource *origin = ucx_map_cstr_get(db_hashes, hash);
+            LocalResource *origin = cxMapGet(db_hashes, cx_hash_key_str(hash));
             if(origin) {
                 local->origin = local_resource_copy(origin, origin->path);
                 // the file is a copied/moved file
                 // check if the file is in the resources_map, because then
                 // it still exists
-                if(ucx_map_cstr_get(resources_map, origin->path)) {
-                    ls_copy = ucx_list_append(ls_copy, local);
+                if(cxMapGet(resources_map, cx_hash_key_str(origin->path))) {
+                    cxListAdd(ls_copy, local);
                 } else {
-                    ls_move = ucx_list_append(ls_move, local);
+                    cxListAdd(ls_move, local);
                     // put file in resources_map to prevent deletion
-                    ucx_map_cstr_put(resources_map, origin->path, local);
+                    cxMapPut(resources_map, cx_hash_key_str(origin->path), local);
                 }
                 // remove list elemend from ls_new
-                if(prev) {
-                    prev->next = next;
-                } else {
-                    ls_new = next;
-                }
-                if(next) {
-                    next->prev = prev;
-                }
+                cxIteratorFlagRemoval(mut_iter);
             }
             
             free(local_path);
-            
-            elm = next;
         }
     }
     
     // find all deleted files and cleanup the database
-    UcxMapIterator i = ucx_map_iterator(db->resources);
+    iter = cxMapIterator(db->resources);
     LocalResource *local;
-    UcxList *removed_res = NULL;
-    UCX_MAP_FOREACH(key, local, i) { 
+    CxList *removed_res = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    cx_foreach(CxMapEntry *, entry, iter) { 
+        LocalResource *local = entry->value;
         // all filtered files should be removed from the database
         if(res_matches_dir_filter(dir, local->path+1)) {
-            ucx_map_cstr_remove(db->resources, local->path);
+            cxMapRemove(db->resources, local->path);
             continue;
         }
-        UCX_FOREACH(elm, dir->filter.tags) {
-            SyncTagFilter *tf = elm->data;
+        CxIterator tag_iter = cxListIterator(dir->filter.tags);
+        cx_foreach(SyncTagFilter *, tf, tag_iter) {
             if(!localres_matches_tags(dir, local, tf)) {
-                ucx_map_cstr_remove(db->resources, local->path);
+                cxMapRemove(db->resources, local->path);
                 continue;
             }
         }
         
-        if(!ucx_map_get(resources_map, key)) {
+        if(!cxMapGet(resources_map, *entry->key)) {
             // The current LocalResource is in the database but doesn't exist
             // in the filesystem anymore. This means the file was deleted
             // and should be deleted on the server
             if(!archive) {
-                ls_delete = ucx_list_append(ls_delete, local);
+                cxListAdd(ls_delete, local);
             } else {
-                removed_res = ucx_list_prepend(removed_res, local);
+                cxListInsert(removed_res, 0, local);
             }
         }
     }
-    UCX_FOREACH(elm, removed_res) {
-        LocalResource *local = elm->data;
-        ucx_map_cstr_remove(db->resources, local->path);
-    }
-    
-    ls_new = ucx_list_sort(ls_new, (cmp_func)resource_path_cmp, NULL);
-    ls_modified = ucx_list_sort(ls_modified, (cmp_func)resource_path_cmp, NULL);
-    ls_conflict = ucx_list_sort(ls_conflict, (cmp_func)resource_path_cmp, NULL);
-    ls_update = ucx_list_sort(ls_update, (cmp_func)resource_path_cmp, NULL);
-    ls_delete = ucx_list_sort(ls_delete, (cmp_func)resource_path_cmp, NULL);
-    ls_move = ucx_list_sort(ls_move, (cmp_func)resource_path_cmp, NULL);
-    ls_copy = ucx_list_sort(ls_copy, (cmp_func)resource_path_cmp, NULL);
-    ls_mkcol = ucx_list_sort(ls_mkcol, (cmp_func)resource_path_cmp, NULL);
+    iter = cxListIterator(removed_res);
+    cx_foreach(LocalResource *, local, iter) {
+        cxMapRemove(db->resources, local->path);
+    }
+    
+    cxListSort(ls_new);
+    cxListSort(ls_modified);
+    cxListSort(ls_conflict);
+    cxListSort(ls_update);
+    cxListSort(ls_delete);
+    cxListSort(ls_move);
+    cxListSort(ls_copy);
+    cxListSort(ls_mkcol);
     
     if(outgoing) {
         print_outgoing(
@@ -2186,8 +2171,11 @@
     int error = 0;
     
     // create collections
-    for(UcxList *elm=ls_mkcol;elm && !sync_shutdown;elm=elm->next) {
-        LocalResource *local_res = elm->data;
+    iter = cxListIterator(ls_mkcol);
+    cx_foreach(LocalResource *, local_res, iter) {
+        if(sync_shutdown) {
+            break;
+        }
         
         DavResource *res = dav_resource_new(sn, local_res->path);
         if(!res) {
@@ -2227,8 +2215,9 @@
 
             // remove old db entry (if it exists)
             // and add add new entry
-            LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path);
-            ucx_map_cstr_put(db->resources, local_res->path, local_res);
+            // TODO: free??
+            LocalResource *dbres = cxMapGet(db->resources, cx_hash_key_str(local_res->path));
+            cxMapPut(db->resources, cx_hash_key_str(local_res->path), local_res);
         }
         
         dav_resource_free(res);
@@ -2240,163 +2229,176 @@
         copy = FALSE;
         ls_copy = ls_move;
     }
-    for(UcxList *elm=ls_copy;elm && !sync_shutdown;elm=elm->next) {
-        LocalResource *local = elm->data;
-        
-        int err = 0;
-        DavResource *res = dav_resource_new(sn, local->path);
-        if(dav_exists(res)) {
-            printf("conflict: %s\n", local->path);
-            local->last_modified = 0;
-            nullfree(local->etag);
-            local->etag = NULL;
-            nullfree(local->hash);
-            local->hash = NULL;
-            local->skipped = TRUE;
-            sync_conflict++;
-        } else {
-            DavResource *origin_res = dav_resource_new(sn, local->origin->path);
-            int origin_changed = remote_resource_is_changed(
-                    sn,
-                    dir,
-                    db,
-                    origin_res,
-                    local->origin,
-                    NULL);
-            if(origin_changed) {
-                // upload with put
-                ls_modified = ucx_list_prepend(ls_modified, local);               
+    iter = cxListIterator(ls_copy);
+    for(int i=0;i<2;i++) {
+        cx_foreach(LocalResource*, local, iter) {
+            if(sync_shutdown) {
+                break;
+            }
+
+            int err = 0;
+            DavResource *res = dav_resource_new(sn, local->path);
+            if(dav_exists(res)) {
+                printf("conflict: %s\n", local->path);
+                local->last_modified = 0;
+                nullfree(local->etag);
+                local->etag = NULL;
+                nullfree(local->hash);
+                local->hash = NULL;
+                local->skipped = TRUE;
+                sync_conflict++;
             } else {
-                printf("%s: %s -> %s\n", copy ? "copy":"move", local->origin->path, local->path);
-                err = sync_move_remote_resource(
+                DavResource *origin_res = dav_resource_new(sn, local->origin->path);
+                int origin_changed = remote_resource_is_changed(
+                        sn,
                         dir,
                         db,
                         origin_res,
-                        local,
-                        copy,
-                        &sync_success);
+                        local->origin,
+                        NULL);
+                if(origin_changed) {
+                    // upload with put
+                    cxListInsert(ls_modified, 0, local);               
+                } else {
+                    printf("%s: %s -> %s\n", copy ? "copy":"move", local->origin->path, local->path);
+                    err = sync_move_remote_resource(
+                            dir,
+                            db,
+                            origin_res,
+                            local,
+                            copy,
+                            &sync_success);
+                }
             }
-        }
-        
-        if(err) {
-            sync_error++;
-            print_resource_error(sn, res->path);
-            ret = -1;
-            error = 1;
-        } else {
-            LocalResource *dbres = ucx_map_cstr_remove(db->resources, local->path);
-            ucx_map_cstr_put(db->resources, local->path, local);
-        }
-        
-        if(copy && !elm->next) {
-            // finished copy, begin move
-            elm->next = ls_move;
-            copy = FALSE;
-        }
+
+            if(err) {
+                sync_error++;
+                print_resource_error(sn, res->path);
+                ret = -1;
+                error = 1;
+            } else {
+                LocalResource *dbres = cxMapGet(db->resources, cx_hash_key_str(local->path));
+                cxMapPut(db->resources, cx_hash_key_str(local->path), local);
+            }
+        }
+        copy = FALSE;
+        iter = cxListIterator(ls_move);
     }
     
     // upload changed files 
-    ls_modified = ucx_list_concat(ls_new, ls_modified);
-    
-    for(UcxList *elm=ls_modified;elm && !sync_shutdown;elm=elm->next) {
-        LocalResource *local_res = elm->data;
-        int err = 0;
-        
-        DavResource *res = dav_resource_new(sn, local_res->path);
-        if(!res) {
-            print_resource_error(sn, local_res->path);
-            ret = -1;
-            sync_error++;
-        } else {
-            DavBool equal = FALSE;
-            DavBool res_conflict = FALSE;
-            int changed = remote_resource_is_changed(sn, dir, db, res, local_res, &equal);
-            if(equal) {
-                char *etag = dav_get_string_property(res, "D:getetag");
-                if(local_res->metadata_updated) {
-                    ls_update = ucx_list_prepend(ls_update, local_res);
-                } else if(etag) {
-                    // update etag in db
-                    if(local_res->etag) {
-                        free(local_res->etag);
+    //ls_modified = ucx_list_concat(ls_new, ls_modified);
+    iter = cxListIterator(ls_new);
+    for(int i=0;i<2;i++) {
+        cx_foreach(LocalResource*, local_res, iter) {
+            if(sync_shutdown) {
+                break;
+            }
+            
+            int err = 0;
+
+            DavResource *res = dav_resource_new(sn, local_res->path);
+            if(!res) {
+                print_resource_error(sn, local_res->path);
+                ret = -1;
+                sync_error++;
+            } else {
+                DavBool equal = FALSE;
+                DavBool res_conflict = FALSE;
+                int changed = remote_resource_is_changed(sn, dir, db, res, local_res, &equal);
+                if(equal) {
+                    char *etag = dav_get_string_property(res, "D:getetag");
+                    if(local_res->metadata_updated) {
+                        cxListInsert(ls_update, 0, local_res);
+                    } else if(etag) {
+                        // update etag in db
+                        if(local_res->etag) {
+                            free(local_res->etag);
+                        }
+                        local_res->etag = strdup(etag);
                     }
-                    local_res->etag = strdup(etag);
+                } else if(cdt && changed) {
+                    printf("conflict: %s\n", local_res->path);
+                    local_res->last_modified = 0;
+                    nullfree(local_res->etag);
+                    local_res->etag = NULL;
+                    nullfree(local_res->hash);
+                    local_res->hash = NULL;
+                    local_res->skipped = TRUE;
+                    sync_conflict++;
+
+                    if(local_res->link_target) {
+                        free(local_res->link_target);
+                        local_res->link_target = local_res->link_target_db;
+                        local_res->link_target_db = NULL;
+                    }
+
+                    res_conflict = TRUE;
+                } else {
+                    if(local_res->link_target) {
+                        printf(
+                                "link: %s -> %s\n",
+                                local_res->path,
+                                local_res->link_target);
+                    } else {
+                        printf("put: %s\n", local_res->path);
+                    }
+                    if(sync_put_resource(dir, res, local_res, &sync_success)) {
+                        sync_error++;
+                        print_resource_error(sn, res->path);
+                        ret = -1;
+                        error = 1;
+
+                        err = 1;
+                    }
                 }
-            } else if(cdt && changed) {
-                printf("conflict: %s\n", local_res->path);
-                local_res->last_modified = 0;
-                nullfree(local_res->etag);
-                local_res->etag = NULL;
-                nullfree(local_res->hash);
-                local_res->hash = NULL;
-                local_res->skipped = TRUE;
-                sync_conflict++;
-                
-                if(local_res->link_target) {
-                    free(local_res->link_target);
-                    local_res->link_target = local_res->link_target_db;
-                    local_res->link_target_db = NULL;
-                }
-                
-                res_conflict = TRUE;
-            } else {
-                if(local_res->link_target) {
-                    printf(
-                            "link: %s -> %s\n",
-                            local_res->path,
-                            local_res->link_target);
-                } else {
-                    printf("put: %s\n", local_res->path);
-                }
-                if(sync_put_resource(dir, res, local_res, &sync_success)) {
-                    sync_error++;
-                    print_resource_error(sn, res->path);
-                    ret = -1;
-                    error = 1;
-                    
-                    err = 1;
+
+                if(!err) {
+                    LocalResource *dbres = cxMapRemoveAndGet(db->resources, cx_hash_key_str(local_res->path));
+                    // in case of a conflict, don't store the resource
+                    // in the db, if it is new
+                    if(!res_conflict || dbres) {
+                        cxMapPut(db->resources, cx_hash_key_str(local_res->path), local_res);
+                    }
                 }
             }
-            
-            if(!err) {
-                LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path);
-                // in case of a conflict, don't store the resource
-                // in the db, if it is new
-                if(!res_conflict || dbres) {
-                    ucx_map_cstr_put(db->resources, local_res->path, local_res);
-                }
-            }
-        }
-        
-        dav_resource_free(res);
+
+            dav_resource_free(res);
+        }
+        iter = cxListIterator(ls_modified);
     }
     
     // metadata updates
-    for(UcxList *elm=ls_update;elm && !sync_shutdown;elm=elm->next) {
-        LocalResource *local_res = elm->data;
+    iter = cxListIterator(ls_update);
+    cx_foreach(LocalResource *, local_res, iter) {
+        if(sync_shutdown) {
+            break;
+        }
         
         DavResource *res = dav_resource_new(sn, local_res->path);       
         if(local_res->metadata_updated) {
             printf("update: %s\n", local_res->path);
             if(!sync_update_metadata(dir, sn, res, local_res)) {
-                LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path);
-                ucx_map_cstr_put(db->resources, local_res->path, local_res);
+                LocalResource *dbres = cxMapGet(db->resources, cx_hash_key_str(local_res->path));
+                cxMapPut(db->resources, cx_hash_key_str(local_res->path), local_res);
             }
         }
     }  
 
     // delete all removed files
-    ls_delete = ucx_list_sort(ls_delete, (cmp_func)resource_pathlen_cmp, NULL);
-    
-    UcxList *cols = NULL;
-    UcxList **col_list = &cols;
-    UcxList *deletelist = ls_delete;
+    cxListSort(ls_delete);
+    
+    CxList *cols = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    CxList *col_list = cols;
+    CxList *deletelist = ls_delete;
     for(int i=0;i<2;i++) {
         // the first iteration deletes everything from ls_delete except
         // all collections, which are stored in cols
         // in the second run all collections will be deleted
-        for(UcxList *elm=deletelist;elm && !sync_shutdown;elm=elm->next) {
-            LocalResource *local = elm->data;
+        iter = cxListIterator(deletelist);
+        cx_foreach(LocalResource *, local, iter) {
+            if(sync_shutdown) {
+                break;
+            }
             if(local->keep) {
                 continue;
             }
@@ -2407,7 +2409,7 @@
                     break;
                 }
             } else {
-                LocalResource *dbres = ucx_map_cstr_remove(db->resources, local->path);
+                LocalResource *dbres = cxMapRemoveAndGet(db->resources, cx_hash_key_str(local->path));
                 //local_resource_free(dbres);
             }
         }
@@ -2477,14 +2479,14 @@
     }
     
     SyncDirectory *dir = NULL;
-    UcxMap *files = NULL;
+    CxMap *files = NULL;
     if(syncdir) {
         dir = scfg_get_dir(syncdir);
     }
     
     LocalResource nres;
     if(a->argc > 0) {
-        files = ucx_map_new(a->argc+8);
+        files = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, a->argc+8);
         // get all specified files and check the syncdir
         SyncDirectory *sd = NULL;
         for(int i=0;i<a->argc;i++) {
@@ -2503,7 +2505,7 @@
                 }
             }
             
-            ucx_map_cstr_put(files, f.path, &nres);
+            cxMapPut(files, cx_hash_key_str(f.path), &nres);
         }
         dir = sd;
     }
@@ -2536,16 +2538,16 @@
     }
     remove_deleted_conflicts(dir, db);
     
-    UcxList *modified = NULL;
-    UcxList *deleted = NULL;
+    CxList *modified = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)localres_cmp_path, CX_STORE_POINTERS);
+    CxList *deleted = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)localres_cmp_path, CX_STORE_POINTERS);
     
     // iterate over all db resources and check if any resource is
     // modified or deleted
-    UcxMapIterator i = ucx_map_iterator(files ? files : db->resources);
-    LocalResource *resource;
-    UCX_MAP_FOREACH(key, resource, i) {
+    CxIterator i = cxMapIterator(files ? files : db->resources);
+    cx_foreach(CxMapEntry *, entry, i) {
+        LocalResource *resource = entry->value;
         if(resource == &nres) {
-            resource = ucx_map_get(db->resources, key);
+            resource = cxMapGet(db->resources, *entry->key);
             if(!resource) {
                 continue;
             }
@@ -2556,7 +2558,7 @@
         if(sys_stat(file_path, &s)) {
             if(errno == ENOENT) {
                 if(restore_removed) {
-                    deleted = ucx_list_prepend(deleted, resource);
+                    cxListAdd(deleted, resource);
                 }
             } else {
                 fprintf(stderr, "Cannot stat file: %s\n", file_path);
@@ -2564,11 +2566,11 @@
             }
         } else {
             if(files) {
-                modified = ucx_list_prepend(modified, resource);
+                cxListAdd(modified, resource);
             } else if(!resource->isdirectory && !S_ISDIR(s.st_mode)) {
                 if(resource->last_modified != s.st_mtime || resource->size != s.st_size) {
                     if(restore_modified) {
-                        modified = ucx_list_prepend(modified, resource);
+                        cxListAdd(modified, resource);
                     }
                 }
             }
@@ -2578,19 +2580,19 @@
     }  
     
     if(files) {
-        ucx_map_free(files);
+        cxMapDestroy(files);
     }
     
     int ret = 0;
     
     // create DavSession
-    Repository *repo = get_repository(sstr(dir->repository));
+    Repository *repo = get_repository(cx_str(dir->repository));
     if(!repo) {
         fprintf(stderr, "Unkown repository %s\n", dir->name);
         return -1;
     }
     DavSession *sn = create_session(a, ctx, repo, dir->collection);
-    ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db);
+    util_regdestr(sn->mp, db, (cx_destructor_func)destroy_db);
     if (cmd_getoption(a, "verbose")) {
         curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L);
         curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr);
@@ -2619,70 +2621,74 @@
     int sync_success = 0;
     int sync_error = 0;
     
-    UcxList *resources = ucx_list_concat(modified, deleted);
-    resources = ucx_list_sort(resources, (cmp_func)localres_cmp_path, NULL);
-    
-    UCX_FOREACH(elm, resources) {
-        LocalResource *resource = elm->data;
-        
-        DavResource *res = dav_get(sn, resource->path, "D:getetag,idav:status,idav:version-collection,idav:split,`idav:content-hash`,idavprops:tags,idavprops:finfo,idavprops:xattributes,idavprops:link");
-        if(!res) {
-            printf("skip: %s\n", resource->path);
-            continue;
-        }
-        char *status = dav_get_string_property(res, "idav:status");
-        if(status && !strcmp(status, "broken")) {
-            fprintf(stderr, "Resource %s broken\n", res->path);
-            continue;
-        }
-        
-        DavResource *vres = NULL;
-        DavBool update_local_entry = TRUE;
-        if(version) {
-            if(dir->versioning->type == VERSIONING_SIMPLE) {
-                vres = versioning_simple_find(res, version);
-            } else if(dir->versioning->type == VERSIONING_DELTAV) {
-                vres = versioning_deltav_find(res, version);
+    // TODO: old code sorted both modified and deleted, is this necessary?
+    //UcxList *resources = ucx_list_concat(modified, deleted);
+    //resources = ucx_list_sort(resources, (cmp_func)localres_cmp_path, NULL);
+    cxListSort(deleted);
+    
+    CxIterator iter = cxListIterator(modified);
+    for(int i=0;i<2;i++) {
+        cx_foreach(LocalResource *, resource, iter) {
+            DavResource *res = dav_get(sn, resource->path, "D:getetag,idav:status,idav:version-collection,idav:split,`idav:content-hash`,idavprops:tags,idavprops:finfo,idavprops:xattributes,idavprops:link");
+            if(!res) {
+                printf("skip: %s\n", resource->path);
+                continue;
             }
-            if(!vres) {
-                fprintf(stderr, "Cannot find  specified version for resource %s\n", res->path);
-                ret = 1;
-                break;
+            char *status = dav_get_string_property(res, "idav:status");
+            if(status && !strcmp(status, "broken")) {
+                fprintf(stderr, "Resource %s broken\n", res->path);
+                continue;
             }
-            
-            // By restoring an old version of a file, the local dir is not
-            // in sync with the server anymore. Mark this file to change
-            // the metadata later, to make sure, the file will be detected
-            // as locally modified, on the next push/pull
-            update_local_entry = FALSE;
-        } else {
-            vres = res;
-        }
-        
-        // download the resource
-        if(!sync_shutdown) {
-            if(resource->isdirectory) {
-                char *local_path = create_local_path(dir, res->path);
-                if(sys_mkdir(local_path) && errno != EEXIST) {
-                    fprintf(stderr,
-                            "Cannot create directory %s: %s",
-                            local_path, strerror(errno));
+
+            DavResource *vres = NULL;
+            DavBool update_local_entry = TRUE;
+            if(version) {
+                if(dir->versioning->type == VERSIONING_SIMPLE) {
+                    vres = versioning_simple_find(res, version);
+                } else if(dir->versioning->type == VERSIONING_DELTAV) {
+                    vres = versioning_deltav_find(res, version);
+                }
+                if(!vres) {
+                    fprintf(stderr, "Cannot find  specified version for resource %s\n", res->path);
+                    ret = 1;
+                    break;
                 }
-                free(local_path);
+
+                // By restoring an old version of a file, the local dir is not
+                // in sync with the server anymore. Mark this file to change
+                // the metadata later, to make sure, the file will be detected
+                // as locally modified, on the next push/pull
+                update_local_entry = FALSE;
             } else {
-                if(sync_get_resource(a, dir, res->path, vres, db, update_local_entry, &sync_success)) {
-                    fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path);
-                    sync_error++;
-                } else if(!update_local_entry) {
-                    LocalResource *lr = ucx_map_cstr_get(db->resources, res->path);
-                    if(lr) {
-                        lr->last_modified = 0;
-                        nullfree(lr->hash);
-                        lr->hash = NULL;
-                    } // else should not happen
+                vres = res;
+            }
+
+            // download the resource
+            if(!sync_shutdown) {
+                if(resource->isdirectory) {
+                    char *local_path = create_local_path(dir, res->path);
+                    if(sys_mkdir(local_path) && errno != EEXIST) {
+                        fprintf(stderr,
+                                "Cannot create directory %s: %s",
+                                local_path, strerror(errno));
+                    }
+                    free(local_path);
+                } else {
+                    if(sync_get_resource(a, dir, res->path, vres, db, update_local_entry, &sync_success)) {
+                        fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path);
+                        sync_error++;
+                    } else if(!update_local_entry) {
+                        LocalResource *lr = cxMapGet(db->resources, cx_hash_key_str(res->path));
+                        if(lr) {
+                            lr->last_modified = 0;
+                            nullfree(lr->hash);
+                            lr->hash = NULL;
+                        } // else should not happen
+                    }
                 }
             }
         }
+        iter = cxListIterator(deleted);
     }
     
     // unlock repository
@@ -2730,25 +2736,25 @@
 
 void print_outgoing(
         CmdArgs *args,
-        UcxList *ls_new,
-        UcxList *ls_modified,
-        UcxList *ls_conflict,
-        UcxList *ls_update,
-        UcxList *ls_delete,
-        UcxList *ls_move,
-        UcxList *ls_copy,
-        UcxList *ls_mkcol)
+        CxList *ls_new,
+        CxList *ls_modified,
+        CxList *ls_conflict,
+        CxList *ls_update,
+        CxList *ls_delete,
+        CxList *ls_move,
+        CxList *ls_copy,
+        CxList *ls_mkcol)
 {
     int64_t total_size = 0;
     
-    size_t len_new = ucx_list_size(ls_new);
-    size_t len_mod = ucx_list_size(ls_modified);
-    size_t len_cnf = ucx_list_size(ls_conflict);
-    size_t len_upd = ucx_list_size(ls_update);
-    size_t len_del = ucx_list_size(ls_delete);
-    size_t len_mov = ucx_list_size(ls_move);
-    size_t len_cpy = ucx_list_size(ls_copy);
-    size_t len_mkc = ucx_list_size(ls_mkcol);
+    size_t len_new = ls_new->size;
+    size_t len_mod = ls_modified->size;
+    size_t len_cnf = ls_conflict->size;
+    size_t len_upd = ls_update->size;
+    size_t len_del = ls_delete->size;
+    size_t len_mov = ls_move->size;
+    size_t len_cpy = ls_copy->size;
+    size_t len_mkc = ls_mkcol->size;
     
     size_t total = len_new + len_mod + len_cnf + len_upd + len_del + len_mov + len_cpy + len_mkc;
     if(total == 0) {
@@ -2761,32 +2767,32 @@
        
     if(ls_mkcol) {
         printf("Directories:\n");
-        UCX_FOREACH(elm, ls_mkcol) {
-            LocalResource *res = elm->data;
+        CxIterator i = cxListIterator(ls_mkcol);
+        cx_foreach(LocalResource *, res, i) {
             printf(" %-49s\n", res->path+1);
             total_size += res->size;
         }
     }
     if(ls_new) {
         printf("New:\n");
-        UCX_FOREACH(elm, ls_new) {
-            LocalResource *res = elm->data;
-            print_outgoging_file(elm->data);
+        CxIterator i = cxListIterator(ls_new);
+        cx_foreach(LocalResource *, res, i) {
+            print_outgoging_file(res);
             total_size += res->size;
         }
     }
     if(ls_modified) {
         printf("Modified:\n");
-        UCX_FOREACH(elm, ls_modified) {
-            LocalResource *res = elm->data;
-            print_outgoging_file(elm->data);
+        CxIterator i = cxListIterator(ls_modified);
+        cx_foreach(LocalResource *, res, i) {
+            print_outgoging_file(res);
             total_size += res->size;
         }
     }
     if(ls_update) {
         printf("Update:\n");
-        UCX_FOREACH(elm, ls_update) {
-            LocalResource *res = elm->data;
+        CxIterator i = cxListIterator(ls_update);
+        cx_foreach(LocalResource *, res, i) {
             char *lastmodified = util_date_str(res->last_modified);
             printf(" %-49s  %12s\n", res->path+1, lastmodified);
             free(lastmodified);
@@ -2794,29 +2800,29 @@
     }
     if(ls_delete) {
         printf("Delete:\n");
-        UCX_FOREACH(elm, ls_delete) {
-            LocalResource *res = elm->data;
+        CxIterator i = cxListIterator(ls_delete);
+        cx_foreach(LocalResource *, res, i) {
             printf(" %s\n", res->path+1);
         }
     }
     if(ls_copy) {
         printf("Copy:\n");
-        UCX_FOREACH(elm, ls_copy) {
-            LocalResource *res = elm->data;
+        CxIterator i = cxListIterator(ls_copy);
+        cx_foreach(LocalResource *, res, i) {
             printf("%s -> %s\n", res->origin->path+1, res->path);
         }
     }
     if(ls_move) {
         printf("Move:\n");
-        UCX_FOREACH(elm, ls_move) {
-            LocalResource *res = elm->data;
+        CxIterator i = cxListIterator(ls_move);
+        cx_foreach(LocalResource *, res, i) {
             printf("%s -> %s\n", res->origin->path+1, res->path);
         }
     }
     if(ls_conflict) {
         printf("Conflict\n");
-        UCX_FOREACH(elm, ls_conflict) {
-            LocalResource *res = elm->data;
+        CxIterator i = cxListIterator(ls_conflict);
+        cx_foreach(LocalResource *, res, i) {
             printf(" %s\n", res->path+1);
         }
     }
@@ -2836,17 +2842,18 @@
     free(total_size_str);
 }
 
-UcxList* local_scan(SyncDirectory *dir, SyncDatabase *db) {
-    UcxList *resources = NULL;
+CxList* local_scan(SyncDirectory *dir, SyncDatabase *db) {
+    CxList *resources = cxLinkedListCreateSimple(CX_STORE_POINTERS);
     
     char *path = strdup("/");
-    UcxList *stack = ucx_list_prepend(NULL, path);
-    while(stack) {
+    CxList *stack = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    cxListInsert(stack, 0, path);
+    while(stack->size > 0) {
         // get a directory path from the stack and read all entries
         // if an entry is a directory, put it on the stack
         
-        char *p = stack->data;
-        stack = ucx_list_remove(stack, stack);
+        char *p = cxListAt(stack, 0);
+        cxListRemove(stack, 0);
         char *local_path = create_local_path(dir, p);
         SYS_DIR local_dir = sys_opendir(local_path);
         
@@ -2864,11 +2871,11 @@
                 LocalResource *res = local_resource_new(dir, db, new_path);
                 if(res) {
                     if(res->isdirectory) {
-                        resources = ucx_list_append(resources, res);
-                        stack = ucx_list_prepend(stack, new_path);
+                        cxListAdd(resources, res);
+                        cxListInsert(stack, 0, new_path);
                         free_new_path = FALSE;
                     } else {
-                        resources = ucx_list_append(resources, res);
+                        cxListAdd(resources, res);
                     }
                 }
                 if(free_new_path) {
@@ -2885,50 +2892,6 @@
     return resources;
 }
 
-UcxList* read_changes(SyncDirectory *dir, SyncDatabase *db) {
-    UcxProperties *parser = ucx_properties_new();
-    parser->delimiter = ':';
-    
-    UcxList *resources = NULL;
-    sstr_t name;
-    sstr_t value;
-    
-    char buf[STDIN_BUF_SIZE];
-    size_t r;
-    while(!feof(stdin)) {
-        r = fread(buf, 1, STDIN_BUF_SIZE, stdin);
-        ucx_properties_fill(parser, buf, r);
-        while(ucx_properties_next(parser, &name, &value)) {
-            if(value.length == 0) {
-                fprintf(stderr, "Wrong input\n");
-                continue;
-            }
-            if(value.ptr[0] == '"'
-                    && value.length > 2
-                    && value.ptr[value.length - 1] == '"')
-            {
-                value.ptr[value.length - 1] = '\0';
-                value.ptr++;
-                value.length -= 2;
-            }
-            value = sstrdup(value);
-            
-            if(!sstrcmp(name, S("put"))) {
-                LocalResource *res = local_resource_new(dir, db, value.ptr);
-                if(res) {
-                    resources = ucx_list_append(resources, res);
-                }
-            } else if(!sstrcmp(name, S("remove"))) {
-                ucx_map_sstr_remove(db->resources, value);
-            }
-            
-            free(value.ptr);
-        }
-    }
-    ucx_properties_free(parser);    
-    
-    return resources;
-}
 
 LocalResource* local_resource_new(SyncDirectory *dir, SyncDatabase *db, char *path) {
     char *file_path = create_local_path(dir, path);
@@ -3051,11 +3014,11 @@
         SyncDirectory *dir,
         SyncDatabase *db,
         LocalResource *res,
-        UcxMap *svrres,
+        CxMap *svrres,
         DavBool restore_removed,
         DavBool restore_modified)
 {
-    LocalResource *db_res = ucx_map_cstr_get(db->resources, res->path);
+    LocalResource *db_res = cxMapGet(db->resources, cx_hash_key_str(res->path));
     res->tags_updated = 0;
     if(db_res) { 
         // copy some metadata from db_res, that localscan does not deliver
@@ -3088,7 +3051,7 @@
         
         // check if the file must be restored on the server
         if(svrres) {
-            DavResource *remote = ucx_map_cstr_get(svrres, res->path);
+            DavResource *remote = cxMapGet(svrres, cx_hash_key_str(res->path));
             if(restore_removed && !remote) {
                 return 1;
             }
@@ -3110,7 +3073,7 @@
             res->tags_updated = 1;
             res->metadata_updated = 1;
         } else if(dir->tagconfig && dir->tagconfig->detect_changes ) {
-            UcxBuffer *tags = sync_get_file_tag_data(dir, res);
+            CxBuffer *tags = sync_get_file_tag_data(dir, res);
             if(tags) {
                 if(db_res->tags_hash) {
                     char *hash = dav_create_hash(tags->space, tags->size);
@@ -3268,9 +3231,9 @@
             // the resource is on the server and the client has no etag
             ret = 1;
         } else if(etag) {
-            sstr_t e = sstr(etag);
-            if(sstrprefix(e, S("W/"))) {
-                e = sstrsubs(e, 2);
+            cxstring e = cx_str(etag);
+            if(cx_strprefix(e, CX_STR("W/"))) {
+                e = cx_strsubs(e, 2);
             }
             if(strcmp(e.ptr, res->etag)) {
                 ret = 1;
@@ -3306,11 +3269,11 @@
         return;
     }
     
-    scstr_t e = scstr(etag);
-    if(sstrprefix(e, S("W/"))) {
-        e = scstrsubs(e, 2);
-    }
-    local->etag = sstrdup(e).ptr;
+    cxstring e = cx_str(etag);
+    if(cx_strprefix(e, CX_STR("W/"))) {
+        e = cx_strsubs(e, 2);
+    }
+    local->etag = cx_strdup(e).ptr;
 }
 
 char* resource_local_path(DavResource *res) {
@@ -3334,9 +3297,9 @@
         return 0;
     } else if(local->blocksize > 0) {
         local_blocksize = (size_t)local->blocksize;
-    } else {
-        UCX_FOREACH(elm, dir->splitconfig) {
-            SplitConfig *sc = elm->data;
+    } else if(dir->splitconfig) {
+        CxIterator i = cxListIterator(dir->splitconfig);
+        cx_foreach(SplitConfig *, sc, i) {
             if(sc->filter) {
                 if(res_matches_filter(sc->filter, local->path)) {
                     continue;
@@ -3462,38 +3425,6 @@
     return ret;
 }
 
-int sync_tags_equal(UcxList *tags1, UcxList *tags2) {
-    if(!tags1) {
-        return tags2 ? 0 : 1;
-    }
-    if(!tags2) {
-        return tags1 ? 0 : 1;
-    }
-    
-    UcxMap *map1 = ucx_map_new(32);
-    UCX_FOREACH(elm, tags1) {
-        DavTag *t = elm->data;
-        ucx_map_cstr_put(map1, t->name, t);
-    }
-    
-    int equal = 1;
-    int i = 0;
-    UCX_FOREACH(elm, tags2) {
-        DavTag *t = elm->data;
-        if(!ucx_map_cstr_get(map1, t->name)) {
-            equal = 0;
-            break;
-        }
-        i++;
-    }
-    
-    if(i != map1->count) {
-        equal = 0;
-    }
-    ucx_map_free(map1);
-    return equal;
-}
-
 int sync_store_metadata(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res) {
     int ret = 0;
     
@@ -3545,12 +3476,12 @@
     // create a map of all currently available local attributes
     ssize_t nelm = 0;
     char **list = xattr_list(path, &nelm);
-    UcxMap *current_xattr = NULL;
+    CxMap *current_xattr = NULL;
     if(nelm > 0) {
-        current_xattr = ucx_map_new(nelm + 8);
+        current_xattr = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, nelm + 8);
         for(int i=0;i<nelm;i++) {
             // use the xattr name as key and store any value
-            ucx_map_cstr_put(current_xattr, list[i], list[i]);
+            cxMapPut(current_xattr, cx_hash_key_str(list[i]), list[i]);
         }
     }
     if(list) {
@@ -3560,7 +3491,7 @@
     // store extended attributes
     size_t nattr = xattr ? xattr->nattr : 0;
     for(int i=0;i<nattr;i++) {
-        sstr_t value = xattr->values[i];
+        cxmutstr value = xattr->values[i];
         if(xattr_set(path, xattr->names[i], value.ptr, value.length)) {
             fprintf(stderr,
                     "Cannot store xattr '%s' for file: %s\n",
@@ -3572,7 +3503,7 @@
             // to detect which xattributes are removed, we remove all new
             // attributes from the map and all remaining attributes must
             // be removed with xattr_remove
-            char *value = ucx_map_cstr_remove(current_xattr, xattr->names[i]);
+            char *value = cxMapRemoveAndGet(current_xattr, cx_hash_key_str(xattr->names[i]));
             if(value) {
                 free(value);
             }
@@ -3580,13 +3511,13 @@
     }
     
     if(current_xattr) {
-        UcxMapIterator i = ucx_map_iterator(current_xattr);
+        CxIterator i = cxMapIteratorValues(current_xattr);
         char *value = NULL;
-        UCX_MAP_FOREACH(key, value, i) {
+        cx_foreach(char *, value, i) {
             (void)xattr_remove(path, value); // don't print error
             free(value);
         }
-        ucx_map_free(current_xattr);
+        cxMapDestroy(current_xattr);
     }
     
     return 0;
@@ -3598,7 +3529,7 @@
     }
     
     char *remote_hash = NULL;
-    UcxList *tags = NULL;
+    CxList *tags = NULL;
     if(dir->tagconfig) {
         DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_PROPS_NS, "tags");
         if(tagsprop) {
@@ -3609,7 +3540,7 @@
     
     DavBool store_tags = FALSE;
     DavBool tags_changed = FALSE;
-    UcxList *local_tags = sync_get_file_tags(dir, local, &tags_changed, NULL);
+    CxList *local_tags = sync_get_file_tags(dir, local, &tags_changed, NULL);
     if(tags_changed) {
         switch(dir->tagconfig->conflict) {
             case TAG_NO_CONFLICT: {
@@ -3626,7 +3557,7 @@
                 break;
             }
             case TAG_MERGE: {
-                UcxList *new_tags = merge_tags(local_tags, tags);
+                CxList *new_tags = merge_tags(local_tags, tags);
                 // TODO: free tags and local_tags
                 tags = new_tags;
                 store_tags = TRUE;   
@@ -3636,7 +3567,7 @@
             }
         }
     } else {
-        if(!sync_tags_equal(tags, local_tags)) {
+        if(!compare_taglists(tags, local_tags)) {
             store_tags = TRUE;
         }
         // TODO: free local_tags
@@ -3661,10 +3592,10 @@
     return ret;
 }
 
-int sync_store_tags_local(SyncDirectory *dir, LocalResource *local, const char *path, UcxList *tags) {
+int sync_store_tags_local(SyncDirectory *dir, LocalResource *local, const char *path, CxList *tags) {
     int ret = 0;
     if(dir->tagconfig->store == TAG_STORE_XATTR) {
-        UcxBuffer *data = NULL;
+        CxBuffer *data = NULL;
         if(tags) {
             switch(dir->tagconfig->local_format) {
                 default: break;
@@ -3704,7 +3635,7 @@
                 } else {
                     free(data_hash);
                 }
-                ucx_buffer_free(data);
+                cxBufferFree(data);
             } else {
                 ret = -1;
             }
@@ -3724,14 +3655,14 @@
     return ret;
 }
 
-UcxBuffer* sync_get_file_tag_data(SyncDirectory *dir, LocalResource *res) {
+CxBuffer* sync_get_file_tag_data(SyncDirectory *dir, LocalResource *res) {
     if(!dir->tagconfig) {
         return NULL;
     }
     if(res->cached_tags) {
         return res->cached_tags;
     }
-    UcxBuffer *buf = NULL;
+    CxBuffer *buf = NULL;
     if(dir->tagconfig->store == TAG_STORE_XATTR) {
         ssize_t tag_length = 0;
         char *local_path = create_local_path(dir, local_resource_path(res));
@@ -3742,7 +3673,7 @@
         free(local_path);
         
         if(tag_length > 0) {
-            buf = ucx_buffer_new(tag_data, (size_t)tag_length, UCX_BUFFER_AUTOFREE);
+            buf = cxBufferCreate(tag_data, (size_t)tag_length, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS);
             buf->size = (size_t)tag_length;
         }
     }
@@ -3750,10 +3681,10 @@
     return buf;
 }
 
-UcxList* sync_get_file_tags(SyncDirectory *dir, LocalResource *res, DavBool *changed, char **newhash) {
+CxList* sync_get_file_tags(SyncDirectory *dir, LocalResource *res, DavBool *changed, char **newhash) {
     if(changed) *changed = FALSE;
     
-    UcxList *tags = NULL;
+    CxList *tags = NULL;
     
     if(!res) {
         return NULL;
@@ -3766,7 +3697,7 @@
         *changed = TRUE;
     }
     if(dir->tagconfig->store == TAG_STORE_XATTR) {
-        UcxBuffer *tag_buf = res->cached_tags ?
+        CxBuffer *tag_buf = res->cached_tags ?
                 res->cached_tags :
                 sync_get_file_tag_data(dir, res);
         
@@ -4011,7 +3942,7 @@
 // this macro is only a workaround for a netbeans bug    
 #define LOG10 log10
 
-static UcxList* upload_parts(
+static CxList* upload_parts(
         LocalResource *local,
         DavResource *res,
         FILE *in,
@@ -4067,7 +3998,8 @@
         return NULL;
     }
     
-    UcxMap *updated_parts_map = ucx_map_new((nblocks/2)+64);
+    CxMap *updated_parts_map = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, (nblocks/2)+64);
+    updated_parts_map->simple_destructor = (cx_destructor_func)filepart_free;
     
     int blockindex = 0;
     int uploaded_parts = 0;
@@ -4121,7 +4053,7 @@
                 FilePart *f = calloc(1, sizeof(FilePart));
                 f->block = blockindex;
                 f->hash = block_hash;
-                ucx_map_cstr_put(updated_parts_map, name, f);
+                cxMapPut(updated_parts_map, cx_hash_key_str(name), f);
             }
             dav_resource_free(part);
             uploaded_parts++;
@@ -4138,8 +4070,7 @@
     
     free(buffer);
     if(*err) {
-        ucx_map_free_content(updated_parts_map, (ucx_destructor)filepart_free);
-        ucx_map_free(updated_parts_map);
+        cxMapDestroy(updated_parts_map);
         return NULL;
     }
     
@@ -4151,18 +4082,17 @@
     
     // get etags from uploaded resources
     // also delete everything, that is not part of the file
-    UcxList *updated_parts = NULL;
+    CxList *updated_parts = cxLinkedListCreateSimple(CX_STORE_POINTERS);
     DavResource *parts = dav_query(res->session, "select D:getetag from %s order by name", res->path);
     if(!parts) {
         print_resource_error(res->session, parts->path);
         *err = 1;
-        ucx_map_free_content(updated_parts_map, (ucx_destructor)filepart_free);
-        ucx_map_free(updated_parts_map);
+        cxMapDestroy(updated_parts_map);
         return NULL;
     }
     DavResource *part = parts->children;
     while(part) {
-        FilePart *fp = ucx_map_cstr_remove(updated_parts_map, part->name);
+        FilePart *fp = cxMapRemoveAndGet(updated_parts_map, cx_hash_key_str(part->name));
         // every part we uploaded is in the map
         // if we get parts that are not in the map, someone else uploaded it
         if(fp) {
@@ -4173,7 +4103,7 @@
                 }
 
                 fp->etag = strdup(etag);
-                updated_parts = ucx_list_append(updated_parts, fp);
+                cxListAdd(updated_parts, fp);
             } // else { wtf is wrong with this resource }
         } else {
             uint64_t name_partnum = 0;
@@ -4200,14 +4130,13 @@
     }
     dav_resource_free_all(parts);
         
-    ucx_map_free_content(updated_parts_map, (ucx_destructor)filepart_free);
-    ucx_map_free(updated_parts_map);
+    cxMapDestroy(updated_parts_map);
     
     *err = 0;
     return updated_parts;
 }
 
-void update_parts(LocalResource *local, UcxList *updates, uint64_t numparts) {
+void update_parts(LocalResource *local, CxList *updates, uint64_t numparts) {
     size_t old_num = local->numparts;
     if(old_num > numparts) {
         // free old parts
@@ -4226,8 +4155,12 @@
         local->numparts = numparts;
     }
     
-    UCX_FOREACH(elm, updates) {
-        FilePart *p = elm->data;
+    if(!updates) {
+        return;
+    }
+    
+    CxIterator i = cxListIterator(updates);
+    cx_foreach(FilePart *, p, i) {
         if(p->block > numparts) {
             // just make sure things don't explode in case some weird stuff
             // is going on
@@ -4285,7 +4218,7 @@
     
     DavBool issplit = split_blocksize == 0 ? FALSE : TRUE;
     int split_err = 0;
-    UcxList *parts = NULL;
+    CxList *parts = NULL;
     uint64_t blockcount = 0;
     
     if(islink) {
@@ -4455,7 +4388,7 @@
     
     LocalResource *local_origin = local->origin;
     if(!copy) {
-        ucx_map_cstr_remove(db->resources, local_origin->path);
+        cxMapRemove(db->resources, cx_hash_key_str(local_origin->path));
     }
     
     // set resource metadata
@@ -4496,7 +4429,7 @@
         DavSession *sn,
         LocalResource *local_res,
         int *counter,
-        UcxList **cols)
+        CxList *cols)
 {
     DavResource *res = dav_get(sn, local_res->path, "D:getetag,idav:split");
     if(!res) {
@@ -4508,7 +4441,7 @@
     if(res->iscollection) {
         DavXmlNode *split = dav_get_property_ns(res, DAV_NS, "split");
         if(cols) {
-            *cols = ucx_list_append(*cols, local_res);
+            cxListAdd(cols, local_res);
         } else if(split || !res->children) {
             printf("delete: %s\n", res->path);
             if(dav_delete(res)) {
@@ -4582,7 +4515,7 @@
         // get local tags
         DavBool changed = 0;
         char *tags_hash = NULL;
-        UcxList *tags = sync_get_file_tags(dir, local, &changed, &tags_hash);
+        CxList *tags = sync_get_file_tags(dir, local, &changed, &tags_hash);
         char *new_remote_hash = nullstrdup(tags_hash);
         if(changed || local->tags_updated) { 
             DavBool store_tags = TRUE;
@@ -4594,7 +4527,7 @@
             if(dav_load_prop(res, &p, 1) && sn->error != DAV_NOT_FOUND) {
                 print_resource_error(sn, res->path);
             }
-            UcxList *remote_tags = NULL;
+            CxList *remote_tags = NULL;
             DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_PROPS_NS, "tags");
             if(tagsprop) {
                 remote_tags = parse_dav_xml_taglist(tagsprop);
@@ -4613,7 +4546,7 @@
                         break;
                     }
                     case TAG_MERGE: {
-                        UcxList *new_tags = merge_tags(tags, remote_tags);
+                        CxList *new_tags = merge_tags(tags, remote_tags);
                         free_taglist(tags);
                         tags = new_tags;
                         
@@ -4706,12 +4639,11 @@
 }
 
 void remove_deleted_conflicts(SyncDirectory *dir, SyncDatabase *db) {
-    char **dc = calloc(sizeof(void*), db->conflict->count);
+    char **dc = calloc(sizeof(void*), db->conflict->size);
     int numdc = 0;
     
-    UcxMapIterator i = ucx_map_iterator(db->conflict);
-    LocalResource *res;
-    UCX_MAP_FOREACH(key, res, i) {
+    CxIterator i = cxMapIteratorValues(db->conflict);
+    cx_foreach(LocalResource *, res, i) {
         char *path = create_local_path(dir, res->path);
         SYS_STAT s;
         if(sys_stat(path, &s)) {
@@ -4727,18 +4659,16 @@
     }
     
     for(int i=0;i<numdc;i++) {
-        ucx_map_cstr_remove(db->conflict, dc[i]);
+        cxMapRemove(db->conflict, cx_hash_key_str(dc[i]));
     }
     
     free(dc);
 }
 
 static void resolve_skipped(SyncDatabase *db) {
-    UcxKey k;
-    LocalResource *res;
-    UcxMapIterator i = ucx_map_iterator(db->resources);
+    CxIterator i = cxMapIteratorValues(db->resources);
     int skipped = 0;
-    UCX_MAP_FOREACH(k, res, i) {
+    cx_foreach(LocalResource *, res, i) {
         if(res->skipped) {
             skipped++;
             fprintf(stderr, "skipped from push: %s\n", res->path);
@@ -4777,9 +4707,9 @@
     int ret = 0;
     
     // remove conflicts
-    int num_conflict = db->conflict->count;
-    ucx_map_free_content(db->conflict, (ucx_destructor)local_resource_free);
-    ucx_map_clear(db->conflict);
+    int num_conflict = db->conflict->size;
+    //ucx_map_free_content(db->conflict, (ucx_destructor)local_resource_free);
+    cxMapClear(db->conflict);
     
     // store db
     if(store_db(db, dir->database, dir->db_settings)) {
@@ -4829,9 +4759,8 @@
     int ret = 0;
     
     // delete all conflict files
-    UcxMapIterator i = ucx_map_iterator(db->conflict);
-    LocalResource *res;
-    UCX_MAP_FOREACH(key, res, i) {
+    CxIterator i = cxMapIterator(db->conflict);
+    cx_foreach(LocalResource*, res, i) {
         printf("delete: %s\n", res->path);
         char *path = create_local_path(dir, res->path);
         if(sys_unlink(path)) {
@@ -4844,8 +4773,8 @@
         }
         free(path);
     }
-    ucx_map_free_content(db->conflict, (ucx_destructor)local_resource_free);
-    ucx_map_clear(db->conflict);
+    //ucx_map_free_content(db->conflict, (ucx_destructor)local_resource_free);
+    cxMapClear(db->conflict);
     
     // store db
     if(store_db(db, dir->database, dir->db_settings)) {
@@ -4893,30 +4822,28 @@
     remove_deleted_conflicts(dir, db);
     
     // get all conflict sources
-    UcxMapIterator i = ucx_map_iterator(db->conflict);
-    LocalResource *res;
-    UcxList* conflict_sources = NULL;
-    UCX_MAP_FOREACH(key, res, i) {
-        conflict_sources = ucx_list_append(conflict_sources, res->conflict_source);
+    CxIterator i = cxMapIteratorValues(db->conflict);
+    CxList* conflict_sources = cxLinkedListCreateSimple(CX_STORE_POINTERS);
+    cx_foreach(LocalResource *, res, i) {
+        cxListAdd(conflict_sources, res->conflict_source);
     }
     
     // print unique conflict sources
-    conflict_sources = ucx_list_sort(conflict_sources, ucx_cmp_str, NULL);
-    UCX_FOREACH(elem, conflict_sources) {
-        char* path = elem->data;
-        if(cmd_getoption(a, "verbose")) {
-            int confl_count = 1;
-            while(elem->next && !strcmp(elem->next->data, path)) {
-                elem = elem->next;
-                ++confl_count;
-            }
-            printf("%s (%d)\n", path, confl_count);
-        } else {
-            printf("%s\n", path);
-            while(elem->next && !strcmp(elem->next->data, path)) {
-                elem = elem->next;
-            }
-        }
+    // TODO: set cmpfunc at map creation
+    conflict_sources->cmpfunc = (cx_compare_func)strcmp;
+    cxListSort(conflict_sources);
+    i = cxListIterator(conflict_sources);
+    char *prev = "";
+    cx_foreach(char *, path, i) {
+        // TODO: implement verbose print   if(cmd_getoption(a, "verbose"))
+        //       printf("%s (%d)\n", path, confl_count);
+        if(!strcmp(path, prev)) {
+            continue;
+        }
+        
+        printf("%s\n", path);
+        
+        prev = path;
     }
     
     // cleanup
@@ -5029,7 +4956,7 @@
         fprintf(stderr, "No versioning configured for syncdir %s\n", dir->name);
     }
     
-    Repository *repo = get_repository(sstr(dir->repository));
+    Repository *repo = get_repository(cx_str(dir->repository));
     if(!repo) {
         fprintf(stderr, "Unknown repository %s\n", dir->repository);
         return -1;
@@ -5043,7 +4970,7 @@
     remove_deleted_conflicts(dir, db);
     
     DavSession *sn = create_session(a, ctx, repo, dir->collection);
-    ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db);
+    util_regdestr(sn->mp, db, (cx_destructor_func)destroy_db);
     if (cmd_getoption(a, "verbose")) {
         curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L);
         curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr);
@@ -5079,23 +5006,23 @@
             }
             
             DavResource *child = vcol->children;
-            UcxList *children = NULL;
+            CxList *children = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)strcmp, CX_STORE_POINTERS);
             while(child) {
-                children = ucx_list_append(children, child);
+                cxListAdd(children, child);
                 child = child->next;
             }
-            children = ucx_list_sort(children, ucx_cmp_str, NULL);
+            cxListSort(children);
             
             DavBool first = 1;
-            UCX_FOREACH(elm, children) {
-                DavResource *c = elm->data;
+            CxIterator i = cxListIterator(children);
+            cx_foreach(DavResource *, c, i) {
                 if(!first) {
                     putchar('\n');
                 }
                 print_resource_version(c, c->name);
                 first = 0;
             }
-            ucx_list_free(children);
+            cxListDestroy(children);
         } while(0);
     } else if(dir->versioning->type == VERSIONING_DELTAV) {
         DavResource *versions = dav_versiontree(res, NULL);
@@ -5271,6 +5198,10 @@
 }
 
 int cmd_tagop(CmdArgs *args, int cmd) {
+    // TODO: port to ucx 3
+    return 1;
+#if 0
+    
     SyncFile file;
     int ret = 0;
     char *path = args->argv[0];
@@ -5293,13 +5224,13 @@
     }
     
     LocalResource *newres = NULL;
-    LocalResource *localres = ucx_map_cstr_get(db->resources, file.path);
+    LocalResource *localres = cxMapGet(db->resources, cx_hash_key_str(file.path));
     if(!localres) {
         newres = calloc(1, sizeof(LocalResource));
         newres->path = strdup(file.path);
         localres = newres;
     }
-    UcxList *tags = NULL;
+    CxList *tags = NULL;
     DavBool store_tags = FALSE;
     
     if(cmd != CMD_TAG_SET) {
@@ -5307,7 +5238,7 @@
         char *tagcolor = NULL; // TODO: get color
 
         tags = sync_get_file_tags(file.dir, localres, NULL, NULL);
-        UcxList *x = NULL;
+        CxList *x = NULL;
         UCX_FOREACH(elm, tags) {
             DavTag *t = elm->data;
             if(cmd == CMD_TAG_LIST) {
@@ -5374,6 +5305,7 @@
     
     free(file.path);
     return ret;
+#endif
 }
 
 int isfileindir(SyncDirectory *dir, const char *path, SyncFile *f) {
@@ -5406,16 +5338,16 @@
     // TODO: normalize path
     DavBool not_in_dir = 0;
     
-    scstr_t fp = scstr(fullpath);
-    scstr_t dp = scstr(dir->path);
+    cxstring fp = cx_str(fullpath);
+    cxstring dp = cx_str(dir->path);
     if(fp.length == dp.length) {
-        if(sstrcmp(fp, dp)) {
+        if(cx_strcmp(fp, dp)) {
             not_in_dir = 1;
         }
     } else if(fp.length < dp.length) {
         not_in_dir = 1;
     } else {
-        if(!sstrprefix(fp, dp)) {
+        if(!cx_strprefix(fp, dp)) {
             not_in_dir = 1;
         } else {
             if(dp.ptr[dp.length-1] == '/') {
@@ -5466,10 +5398,8 @@
     } else {
         SyncDirectory *target = NULL;
         
-        UcxMapIterator i = scfg_directory_iterator();
-        UcxKey k;
-        SyncDirectory *dir;
-        UCX_MAP_FOREACH(key, dir, i) {
+        CxIterator i = scfg_directory_iterator();
+        cx_foreach(SyncDirectory *, dir, i) {
             if(isfileindir(dir, path, f)) {
                 if(target) {
                     return 5;
@@ -5500,11 +5430,17 @@
 
 
 int cmd_add_directory(CmdArgs *args) {
+    /*
     if(!get_repositories()) {
         fprintf(stderr, "No repositories available. Run 'dav add-repository' first.\n");
         fprintf(stderr, "Abort\n");
         return -1;
     }
+    */
+    
+    // TODO: port to ucx 3
+    return 1;
+#if 0
     
     printf("Each sync directory must have an unique name.\n");
     char *name = assistant_getcfg("name");
@@ -5525,10 +5461,9 @@
     }
     
     printf("Specify webdav repository.\n");
-    UcxList *repos = get_repositories();
+    CxIterator repos = get_repositories();
     int i = 0;
-    UCX_FOREACH(elm, repos) {
-        Repository *r = elm->data;
+    cx_foreach(Repository *, r, repos) {
         printf("%d) %s\n", i, r->name);
         i++;
     }
@@ -5590,12 +5525,12 @@
     free(db);
     
     return ret;
+#endif
 }
 
 int cmd_list_dirs() {
-    UcxMapIterator iter = scfg_directory_iterator();
-    SyncDirectory *dir;
-    UCX_MAP_FOREACH(key, dir, iter) {
+    CxIterator iter = scfg_directory_iterator();
+    cx_foreach(SyncDirectory *, dir, iter) {
         printf("%s\n", dir->name);
     }
     return 0;
@@ -5604,19 +5539,18 @@
 int cmd_check_repositories(CmdArgs *a) {
     int ret = EXIT_SUCCESS;
 
-    UcxList *reponames = NULL;
+    CxList *reponames = cxLinkedListCreateSimple(CX_STORE_POINTERS);
     {
-        UcxMapIterator iter = scfg_directory_iterator();
-        SyncDirectory *dir;
-        UCX_MAP_FOREACH(key, dir, iter) {
-            reponames = ucx_list_append(reponames, dir->repository);
-        }
-    }
-
-    UCX_FOREACH(listelem, reponames) {
-        char *reponame = listelem->data;
+        CxIterator iter = scfg_directory_iterator();
+        cx_foreach(SyncDirectory *, dir, iter) {
+            cxListAdd(reponames, dir->repository);
+        }
+    }
+    
+    CxIterator iter = cxListIterator(reponames);
+    cx_foreach(char *, reponame, iter) {
         printf("Checking %s... ", reponame);
-        Repository* repo = get_repository(sstr(reponame));
+        Repository* repo = get_repository(cx_str(reponame));
         if (!repo) {
             printf(" not found in config.xml!\n");
             ret = EXIT_FAILURE;
@@ -5640,13 +5574,13 @@
         }
     }
     
-    ucx_list_free(reponames);
+    cxListDestroy(reponames);
     
     return ret;
 }
 
 char* create_locktoken_file(const char *syncdirname, const char *locktoken) {
-    sstr_t fname = ucx_sprintf("locktoken-%s.txt", syncdirname);
+    cxmutstr fname = cx_asprintf("locktoken-%s.txt", syncdirname);
     char *path = config_file_path(fname.ptr);
     free(fname.ptr);
     

mercurial