dav/sync.c

changeset 747
efbd59642577
parent 739
bba6a6e221b4
child 749
bbadf84cfc2d
equal deleted inserted replaced
746:a569148841ff 747:efbd59642577
34 #include <signal.h> 34 #include <signal.h>
35 #include <time.h> 35 #include <time.h>
36 #include <utime.h> 36 #include <utime.h>
37 #include <libxml/xmlerror.h> 37 #include <libxml/xmlerror.h>
38 #include <sys/types.h> 38 #include <sys/types.h>
39 #include <ucx/string.h> 39 #include <cx/string.h>
40 #include <ucx/utils.h> 40 #include <cx/utils.h>
41 #include <ucx/properties.h> 41 #include <cx/hash_map.h>
42 #include <cx/printf.h>
42 #include <dirent.h> 43 #include <dirent.h>
43 44
44 #include <math.h> 45 #include <math.h>
45 46
46 #include <libidav/webdav.h> 47 #include <libidav/webdav.h>
353 return local_path; 354 return local_path;
354 } 355 }
355 356
356 static int res_matches_filter(Filter *filter, char *res_path) { 357 static int res_matches_filter(Filter *filter, char *res_path) {
357 // include/exclude filter 358 // include/exclude filter
358 UCX_FOREACH(inc, filter->include) { 359 CxIterator i = cxListIterator(filter->include);
359 regex_t* pattern = (regex_t*) inc->data; 360 cx_foreach(regex_t*, pattern, i) {
360 if (regexec(pattern, res_path, 0, NULL, 0) == 0) { 361 if (regexec(pattern, res_path, 0, NULL, 0) == 0) {
361 UCX_FOREACH(exc, filter->exclude) { 362 CxIterator e = cxListIterator(filter->exclude);
362 regex_t* pattern = (regex_t*) exc->data; 363 cx_foreach(regex_t*, expat, e) {
363 if (regexec(pattern, res_path, 0, NULL, 0) == 0) { 364 if (regexec(expat, res_path, 0, NULL, 0) == 0) {
364 return 1; 365 return 1;
365 } 366 }
366 } 367 }
367 return 0; 368 return 0;
368 } 369 }
371 } 372 }
372 373
373 static int res_matches_dir_filter(SyncDirectory *dir, char *res_path) { 374 static int res_matches_dir_filter(SyncDirectory *dir, char *res_path) {
374 // trash filter 375 // trash filter
375 if (dir->trash) { 376 if (dir->trash) {
376 sstr_t rpath = sstr(util_concat_path(dir->path, res_path)); 377 cxmutstr rpath = cx_mutstr(util_concat_path(dir->path, res_path));
377 if (util_path_isrelated(dir->trash, rpath.ptr)) { 378 if (util_path_isrelated(dir->trash, rpath.ptr)) {
378 free(rpath.ptr); 379 free(rpath.ptr);
379 return 1; 380 return 1;
380 } 381 }
381 free(rpath.ptr); 382 free(rpath.ptr);
405 if(res->iscollection) { 406 if(res->iscollection) {
406 return 1; 407 return 1;
407 } 408 }
408 409
409 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_PROPS_NS, "tags"); 410 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_PROPS_NS, "tags");
410 UcxList *res_tags = parse_dav_xml_taglist(tagsprop); 411 CxList *res_tags = parse_dav_xml_taglist(tagsprop);
411 412
412 int ret = matches_tagfilter(res_tags, tagfilter); 413 int ret = matches_tagfilter(res_tags, tagfilter);
413 414
414 ucx_list_free_content(res_tags, (ucx_destructor) free_dav_tag); 415 cxListDestroy(res_tags);
415 ucx_list_free(res_tags);
416 416
417 return ret; 417 return ret;
418 } 418 }
419 419
420 static int localres_matches_tags( 420 static int localres_matches_tags(
434 if(res->isdirectory) { 434 if(res->isdirectory) {
435 return 1; 435 return 1;
436 } 436 }
437 437
438 DavBool changed = 0; 438 DavBool changed = 0;
439 UcxList *res_tags = sync_get_file_tags(dir, res, &changed, NULL); 439 CxList *res_tags = sync_get_file_tags(dir, res, &changed, NULL);
440 440
441 int ret = matches_tagfilter(res_tags, tagfilter); 441 int ret = matches_tagfilter(res_tags, tagfilter);
442 UCX_FOREACH(elm, res_tags) { 442 CxIterator i = cxListIterator(res_tags);
443 DavTag *t = elm->data; 443 cxListDestroy(res_tags);
444 free_dav_tag(t);
445 }
446 ucx_list_free(res_tags);
447 return ret; 444 return ret;
448 } 445 }
449 446
450 static DavSession* create_session(CmdArgs *a, DavContext *ctx, Repository *repo, char *collection) { 447 static DavSession* create_session(CmdArgs *a, DavContext *ctx, Repository *repo, char *collection) {
451 int flags = get_repository_flags(repo); 448 int flags = get_repository_flags(repo);
508 } 505 }
509 fprintf(stderr, "\n"); 506 fprintf(stderr, "\n");
510 } 507 }
511 508
512 static void localres_keep(SyncDatabase *db, const char *path) { 509 static void localres_keep(SyncDatabase *db, const char *path) {
513 LocalResource *local = ucx_map_cstr_remove(db->resources, path); 510 LocalResource *local = cxMapRemoveAndGet(db->resources, cx_hash_key_str(path));
514 if(local) { 511 if(local) {
515 local->keep = TRUE; 512 local->keep = TRUE;
516 } 513 }
517 } 514 }
518 515
526 return 0; 523 return 0;
527 } 524 }
528 return 1; 525 return 1;
529 } 526 }
530 527
531 void res2map(DavResource *root, UcxMap *map) { 528 void res2map(DavResource *root, CxMap *map) {
532 UcxList *stack = ucx_list_prepend(NULL, root->children); 529 CxList *stack = cxLinkedListCreateSimple(CX_STORE_POINTERS);
533 while(stack) { 530 cxListInsert(stack, 0, root->children);
534 DavResource *res = stack->data; 531 while(stack->size > 0) {
535 stack = ucx_list_remove(stack, stack); 532 DavResource *res = cxListAt(stack, 0);
533 cxListRemove(stack, 0);
536 534
537 while(res) { 535 while(res) {
538 ucx_map_cstr_put(map, res->path, res); 536 cxMapPut(map, cx_hash_key_str(res->path), res);
539 537
540 if(res->children) { 538 if(res->children) {
541 stack = ucx_list_prepend(stack, res->children); 539 cxListInsert(stack, 0, res->children);
542 } 540 }
543 res = res->next; 541 res = res->next;
544 } 542 }
545 } 543 }
544 cxListDestroy(stack);
546 } 545 }
547 546
548 int cmd_pull(CmdArgs *a, DavBool incoming) { 547 int cmd_pull(CmdArgs *a, DavBool incoming) {
549 if(a->argc != 1) { 548 if(a->argc != 1) {
550 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many"); 549 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many");
573 fprintf(stderr, "Command 'pull' is not allowed for this sync dir\n"); 572 fprintf(stderr, "Command 'pull' is not allowed for this sync dir\n");
574 print_allowed_cmds(dir); 573 print_allowed_cmds(dir);
575 return -1; 574 return -1;
576 } 575 }
577 576
578 Repository *repo = get_repository(sstr(dir->repository)); 577 Repository *repo = get_repository(cx_str(dir->repository));
579 if(!repo) { 578 if(!repo) {
580 fprintf(stderr, "Unknown repository %s\n", dir->repository); 579 fprintf(stderr, "Unknown repository %s\n", dir->repository);
581 return -1; 580 return -1;
582 } 581 }
583 582
586 fprintf(stderr, "Cannot load database file: %s\n", dir->database); 585 fprintf(stderr, "Cannot load database file: %s\n", dir->database);
587 return -1; 586 return -1;
588 } 587 }
589 remove_deleted_conflicts(dir, db); 588 remove_deleted_conflicts(dir, db);
590 589
591 UcxMap *hashes = NULL; 590 CxMap *hashes = NULL;
592 if(SYNC_HASHING(dir)) { 591 if(SYNC_HASHING(dir)) {
593 hashes = create_hash_index(db); 592 hashes = create_hash_index(db);
594 } 593 }
595 594
596 DavSession *sn = create_session(a, ctx, repo, dir->collection); 595 DavSession *sn = create_session(a, ctx, repo, dir->collection);
597 ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db); 596 util_regdestr(sn->mp, db, (cx_destructor_func)destroy_db);
598 if (cmd_getoption(a, "verbose")) { 597 if (cmd_getoption(a, "verbose")) {
599 curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L); 598 curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L);
600 curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr); 599 curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr);
601 } 600 }
602 601
662 int sync_success = 0; 661 int sync_success = 0;
663 int sync_delete = 0; 662 int sync_delete = 0;
664 int sync_error = 0; 663 int sync_error = 0;
665 int sync_conflict = 0; 664 int sync_conflict = 0;
666 665
667 UcxList *res_modified = NULL; 666 CxList *res_modified = cxLinkedListCreateSimple(CX_STORE_POINTERS);
668 UcxList *res_new = NULL; 667 CxList *res_new = cxLinkedListCreateSimple(CX_STORE_POINTERS);
669 UcxList *res_moved = NULL; // type: MovedFile 668 CxList *res_moved = cxLinkedListCreateSimple(CX_STORE_POINTERS); // type: MovedFile
670 UcxList *res_link = NULL; 669 CxList *res_link = cxLinkedListCreateSimple(CX_STORE_POINTERS);
671 UcxList *res_conflict = NULL; 670 CxList *res_conflict = cxLinkedListCreateSimple(CX_STORE_POINTERS);
672 UcxList *res_mkdir = NULL; 671 CxList *res_mkdir = cxLinkedListCreateSimple(CX_STORE_POINTERS);
673 UcxList *res_metadata = NULL; 672 CxList *res_metadata = cxLinkedListCreateSimple(CX_STORE_POINTERS);
674 UcxList *res_broken = NULL; 673 CxList *res_broken = cxLinkedListCreateSimple(CX_STORE_POINTERS);
675 UcxMap *lres_removed = ucx_map_new(16); // type: LocalResource* 674 CxMap *lres_removed = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); // type: LocalResource*
676 675
677 //UcxMap *svrres = ucx_map_new(db->resources->count); 676 //UcxMap *svrres = ucx_map_new(db->resources->count);
678 UcxMap *dbres = ucx_map_clone(db->resources, NULL, NULL); 677 CxMap *dbres = NULL; // TODO: ucx_map_clone(db->resources, NULL, NULL);
679 678
680 UcxList *stack = ucx_list_prepend(NULL, ls->children); 679 CxList *stack = cxLinkedListCreateSimple(CX_STORE_POINTERS);
681 while(stack) { 680 cxListInsert(stack, 0, ls->children);
682 DavResource *res = stack->data; 681 while(stack->size > 0) {
683 stack = ucx_list_remove(stack, stack); 682 DavResource *res = cxListAt(stack, 0);
683 cxListRemove(stack, 0);
684 684
685 while(res) { 685 while(res) {
686 DavBool res_filtered = FALSE; 686 DavBool res_filtered = FALSE;
687 if (res_matches_dir_filter(dir, res->path)) { 687 if (res_matches_dir_filter(dir, res->path)) {
688 res_filtered = TRUE; 688 res_filtered = TRUE;
689 } else { 689 } else {
690 UCX_FOREACH(elm, dir->filter.tags) { 690 CxIterator iter = cxListIterator(dir->filter.tags);
691 SyncTagFilter *tf = elm->data; 691 cx_foreach(SyncTagFilter *, tf, iter) {
692 if(!res_matches_tags(res, tf)) { 692 if(!res_matches_tags(res, tf)) {
693 res_filtered = TRUE; 693 res_filtered = TRUE;
694 break; 694 break;
695 } 695 }
696 } 696 }
712 712
713 char *status = dav_get_string_property(res, "idav:status"); 713 char *status = dav_get_string_property(res, "idav:status");
714 if(status && !strcmp(status, "broken")) { 714 if(status && !strcmp(status, "broken")) {
715 res = res->next; 715 res = res->next;
716 localres_keep(db, res->path); 716 localres_keep(db, res->path);
717 res_broken = ucx_list_append(res_broken, res); 717 cxListAdd(res_broken, res);
718 continue; 718 continue;
719 } 719 }
720 720
721 // check if a resource has changed on the server 721 // check if a resource has changed on the server
722 int change = resource_get_remote_change(a, res, dir, db); 722 int change = resource_get_remote_change(a, res, dir, db);
723 switch(change) { 723 switch(change) {
724 case REMOTE_NO_CHANGE: break; 724 case REMOTE_NO_CHANGE: break;
725 case REMOTE_CHANGE_MODIFIED: { 725 case REMOTE_CHANGE_MODIFIED: {
726 res_modified = ucx_list_append(res_modified, res); 726 cxListAdd(res_modified, res);
727 break; 727 break;
728 } 728 }
729 case REMOTE_CHANGE_NEW: { 729 case REMOTE_CHANGE_NEW: {
730 res_new = ucx_list_append(res_new, res); 730 cxListAdd(res_new, res);
731 break; 731 break;
732 } 732 }
733 case REMOTE_CHANGE_DELETED: break; // never happens 733 case REMOTE_CHANGE_DELETED: break; // never happens
734 case REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED: { 734 case REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED: {
735 res_conflict = ucx_list_append(res_conflict, res); 735 cxListAdd(res_conflict, res);
736 break; 736 break;
737 } 737 }
738 case REMOTE_CHANGE_METADATA: { 738 case REMOTE_CHANGE_METADATA: {
739 res_metadata = ucx_list_append(res_metadata, res); 739 cxListAdd(res_metadata, res);
740 break; 740 break;
741 } 741 }
742 case REMOTE_CHANGE_MKDIR: { 742 case REMOTE_CHANGE_MKDIR: {
743 res_mkdir = ucx_list_append(res_mkdir, res); 743 cxListAdd(res_mkdir, res);
744 break; 744 break;
745 } 745 }
746 case REMOTE_CHANGE_LINK: { 746 case REMOTE_CHANGE_LINK: {
747 res_link = ucx_list_append(res_link, res); 747 cxListAdd(res_link, res);
748 break; 748 break;
749 } 749 }
750 } 750 }
751 751
752 // remove every server resource from dbres 752 // remove every server resource from dbres
753 // all remaining elements are the resources that are removed 753 // all remaining elements are the resources that are removed
754 // on the server 754 // on the server
755 ucx_map_cstr_remove(dbres, res->path); 755 cxMapRemove(dbres, cx_hash_key_str(res->path));
756 756
757 if(!dav_get_property_ns(res, DAV_NS, "split") && res->children) { 757 if(!dav_get_property_ns(res, DAV_NS, "split") && res->children) {
758 stack = ucx_list_prepend(stack, res->children); 758 cxListInsert(stack, 0, res->children);
759 } 759 }
760 res = res->next; 760 res = res->next;
761 } 761 }
762 } 762 }
763 763
764 // find deleted resources 764 // find deleted resources
765 // svrres currently contains all resources from the server 765 // svrres currently contains all resources from the server
766 // and will replace the current db->resources map later 766 // and will replace the current db->resources map later
767 UcxMapIterator i = ucx_map_iterator(dbres); 767 CxIterator i = cxMapIteratorValues(dbres);
768 LocalResource *local; 768 cx_foreach(LocalResource *, local, i) {
769 UCX_MAP_FOREACH(key, local, i) {
770 if (res_matches_dir_filter(dir, local->path)) { 769 if (res_matches_dir_filter(dir, local->path)) {
771 continue; 770 continue;
772 } 771 }
773 if(!local->keep) { 772 if(!local->keep) {
774 ucx_map_cstr_put(lres_removed, local->path, local); 773 cxMapPut(lres_removed, cx_hash_key_str(local->path), local);
775 if(lres_removed->count > lres_removed->size * 2) { 774 if(lres_removed->size > lres_removed->size * 2) {
776 ucx_map_rehash(lres_removed); 775 cxMapRehash(lres_removed);
777 } 776 }
778 } 777 }
779 } 778 }
780 779
781 // 780 //
782 // BEGIN PULL 781 // BEGIN PULL
783 // 782 //
784 783
785 // the first thing we need are all directories to put the files in 784 // the first thing we need are all directories to put the files in
786 UCX_FOREACH(elm, res_mkdir) { 785 i = cxListIterator(res_mkdir);
787 DavResource *res = elm->data; 786 cx_foreach(DavResource *, res, i) {
788 if(sync_get_collection(a, dir, res, db)) { 787 if(sync_get_collection(a, dir, res, db)) {
789 sync_error++; 788 sync_error++;
790 } 789 }
791 } 790 }
792 791
793 // we need a map for all conflicts for fast lookups 792 // we need a map for all conflicts for fast lookups
794 UcxMap *conflicts = ucx_map_new(ucx_list_size(res_conflict)+16); 793 CxMap *conflicts = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, res_conflict->size+16);
795 UCX_FOREACH(elm, res_conflict) { 794 i = cxListIterator(res_conflict);
796 DavResource *res = elm->data; 795 cx_foreach(DavResource *, res, i) {
797 ucx_map_cstr_put(conflicts, res->path, res); 796 cxMapPut(conflicts, cx_hash_key_str(res->path), res);
798 } 797 }
799 798
800 if(SYNC_HASHING(dir)) { 799 if(SYNC_HASHING(dir)) {
801 // check for moved/copied files 800 // check for moved/copied files
802 UcxList *elm = res_new;
803 UcxList *prev = NULL;
804 UcxList *next = NULL;
805 SYS_STAT s; 801 SYS_STAT s;
806 for(;elm;elm=next) { 802 CxMutIterator mut_iter = cxListMutIterator(res_new);
807 DavResource *res = elm->data; 803 cx_foreach(DavResource *, res, mut_iter) {
808 prev = elm->prev;
809 next = elm->next;
810
811 if(dav_get_property_ns(res, DAV_PROPS_NS, "link")) { 804 if(dav_get_property_ns(res, DAV_PROPS_NS, "link")) {
812 continue; 805 continue;
813 } 806 }
814 807
815 char *hash = sync_get_content_hash(res); 808 char *hash = sync_get_content_hash(res);
816 if(!hash) { 809 if(!hash) {
817 continue; 810 continue;
818 } 811 }
819 812
820 LocalResource *local = ucx_map_cstr_get(hashes, hash); 813 LocalResource *local = cxMapGet(hashes, cx_hash_key_str(hash));
821 if(!local) { 814 if(!local) {
822 continue; 815 continue;
823 } 816 }
824 817
825 char *local_path = util_concat_path(dir->path, local_resource_path(local)); 818 char *local_path = util_concat_path(dir->path, local_resource_path(local));
831 } 824 }
832 825
833 MovedFile *mf = malloc(sizeof(MovedFile)); 826 MovedFile *mf = malloc(sizeof(MovedFile));
834 mf->content = local; 827 mf->content = local;
835 mf->resource = res; 828 mf->resource = res;
836 if(ucx_map_cstr_remove(lres_removed, local->path)) { 829 if(cxMapRemoveAndGet(lres_removed, cx_hash_key_str(local->path))) {
837 mf->copy = FALSE; 830 mf->copy = FALSE;
838 } else { 831 } else {
839 mf->copy = TRUE; 832 mf->copy = TRUE;
840 } 833 }
841 834
842 res_moved = ucx_list_append(res_moved, mf); 835 cxListAdd(res_moved, mf);
843 836
844 // remove item from res_new 837 // remove item from res_new
845 if(prev) { 838 cxIteratorFlagRemoval(mut_iter);
846 prev->next = next;
847 } else {
848 res_new = next;
849 }
850 if(next) {
851 next->prev = prev;
852 }
853 } 839 }
854 } 840 }
855 841
856 // do copy/move operations 842 // do copy/move operations
857 UCX_FOREACH(elm, res_moved) { 843 i = cxListIterator(res_moved);
858 MovedFile *mf = elm->data; 844 cx_foreach(MovedFile *, mf, i) {
859 if(sync_shutdown) { 845 if(sync_shutdown) {
860 break; 846 break;
861 } 847 }
862 848
863 DavBool issplit = dav_get_property_ns(mf->resource, DAV_NS, "split") ? 1 : 0; 849 DavBool issplit = dav_get_property_ns(mf->resource, DAV_NS, "split") ? 1 : 0;
864 if(ucx_map_cstr_get(conflicts, mf->resource->path)) { 850 if(cxMapGet(conflicts, cx_hash_key_str(mf->resource->path))) {
865 rename_conflict_file(dir, db, mf->resource->path, issplit); 851 rename_conflict_file(dir, db, mf->resource->path, issplit);
866 sync_conflict++; 852 sync_conflict++;
867 } 853 }
868 854
869 // move file 855 // move file
872 sync_error++; 858 sync_error++;
873 } 859 }
874 } 860 }
875 861
876 // download all new, modified and conflict files 862 // download all new, modified and conflict files
877 UcxList *download = ucx_list_concat(res_modified, res_conflict); 863 for(int n=0;n<4;n++) {
878 download = ucx_list_concat(res_new, download); 864 CxList *ls;
879 download = ucx_list_concat(download, res_link); 865 if(n == 0) {
880 UCX_FOREACH(elm, download) { 866 ls = res_new;
881 DavResource *res = elm->data; 867 } else if(n == 1) {
868 ls = res_modified;
869 } else if(n == 2) {
870 ls = res_conflict;
871 } else {
872 ls = res_link;
873 }
874 CxIterator iter = cxListIterator(ls);
875 cx_foreach(DavResource *, res, iter) {
876 if(sync_shutdown) {
877 break;
878 }
879
880 DavBool issplit = dav_get_property_ns(res, DAV_NS, "split") ? 1 : 0;
881 if(cxMapGet(conflicts, cx_hash_key_str(res->path))) {
882 rename_conflict_file(dir, db, res->path, issplit);
883 sync_conflict++;
884 }
885
886 // download the resource
887 if(sync_get_resource(a, dir, res->path, res, db, TRUE, &sync_success)) {
888 fprintf(stderr, "resource download failed: %s\n", res->path);
889 sync_error++;
890 }
891 }
892 }
893
894 // update metadata
895 i = cxListIterator(res_metadata);
896 cx_foreach(DavResource *, res, i) {
882 if(sync_shutdown) { 897 if(sync_shutdown) {
883 break; 898 break;
884 } 899 }
885 900
886 DavBool issplit = dav_get_property_ns(res, DAV_NS, "split") ? 1 : 0; 901 LocalResource *local = cxMapGet(db->resources, cx_hash_key_str(res->path));
887 if(ucx_map_cstr_get(conflicts, res->path)) {
888 rename_conflict_file(dir, db, res->path, issplit);
889 sync_conflict++;
890 }
891
892 // download the resource
893 if(sync_get_resource(a, dir, res->path, res, db, TRUE, &sync_success)) {
894 fprintf(stderr, "resource download failed: %s\n", res->path);
895 sync_error++;
896 }
897 }
898
899 // update metadata
900 UCX_FOREACH(elm, res_metadata) {
901 DavResource *res = elm->data;
902 if(sync_shutdown) {
903 break;
904 }
905
906 LocalResource *local = ucx_map_cstr_get(db->resources, res->path);
907 if(local) { 902 if(local) {
908 printf("update: %s\n", res->path); 903 printf("update: %s\n", res->path);
909 char *res_path = resource_local_path(res); 904 char *res_path = resource_local_path(res);
910 char *local_path = create_local_path(dir, res->path); 905 char *local_path = create_local_path(dir, res->path);
911 free(res_path); 906 free(res_path);
927 "Cannot update metadata of file %s: not in database\n", 922 "Cannot update metadata of file %s: not in database\n",
928 res->path); 923 res->path);
929 } 924 }
930 } 925 }
931 926
932 UcxList *rmdirs = NULL; 927 CxList *rmdirs = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_pathlen_cmp, CX_STORE_POINTERS);
933 UcxMapIterator mi = ucx_map_iterator(lres_removed); 928 i = cxMapIteratorValues(lres_removed);
934 LocalResource *removed_res; 929 LocalResource *removed_res;
935 UcxKey key; 930 cx_foreach(LocalResource *, removed_res, i) {
936 UCX_MAP_FOREACH(key, removed_res, mi) {
937 if(sync_shutdown) { 931 if(sync_shutdown) {
938 break; 932 break;
939 } 933 }
940 934
941 int ret = sync_remove_local_resource(dir, removed_res); 935 int ret = sync_remove_local_resource(dir, removed_res);
942 if(ret == -1) { 936 if(ret == -1) {
943 rmdirs = ucx_list_append(rmdirs, removed_res); 937 cxListAdd(rmdirs, removed_res);
944 } else if(ret == 0) { 938 } else if(ret == 0) {
945 LocalResource *local = ucx_map_cstr_remove(db->resources, removed_res->path); 939 LocalResource *local = cxMapRemoveAndGet(db->resources, cx_hash_key_str(removed_res->path));
946 if(local) { 940 if(local) {
947 local_resource_free(local); 941 local_resource_free(local);
948 } 942 }
949 sync_delete++; 943 sync_delete++;
950 } 944 }
951 } 945 }
952 ucx_map_free(lres_removed); 946 cxMapDestroy(lres_removed);
953 947
954 // sort dir list, we need to delete dirs with higher depth first 948 // sort dir list, we need to delete dirs with higher depth first
955 rmdirs = ucx_list_sort(rmdirs, (cmp_func)resource_pathlen_cmp, NULL); 949 cxListSort(rmdirs);
956 // delete dirs 950 // delete dirs
957 UCX_FOREACH(elm, rmdirs) { 951 i = cxListIterator(rmdirs);
958 LocalResource *local_dir = elm->data; 952 cx_foreach(LocalResource *, local_dir, i) {
959 if(!sync_remove_local_directory(dir, local_dir)) { 953 if(!sync_remove_local_directory(dir, local_dir)) {
960 // dir successfully removed, now remove the related db entry 954 // dir successfully removed, now remove the related db entry
961 LocalResource *local = ucx_map_cstr_remove(db->resources, local_dir->path); 955 LocalResource *local = cxMapRemoveAndGet(db->resources, cx_hash_key_str(local_dir->path));
962 if(local) { 956 if(local) {
963 local_resource_free(local); 957 local_resource_free(local);
964 } 958 }
965 sync_delete++; 959 sync_delete++;
966 } 960 }
1028 DavBool iscollection = res->iscollection && !issplit; 1022 DavBool iscollection = res->iscollection && !issplit;
1029 1023
1030 RemoteChangeType type = cmd_getoption(a, "conflict") ? 1024 RemoteChangeType type = cmd_getoption(a, "conflict") ?
1031 REMOTE_CHANGE_MODIFIED : REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED; 1025 REMOTE_CHANGE_MODIFIED : REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED;
1032 1026
1033 LocalResource *local = ucx_map_cstr_get(db->resources, res->path); 1027 LocalResource *local = cxMapGet(db->resources, cx_hash_key_str(res->path));
1034 char *local_path = create_local_path(dir, res->path); 1028 char *local_path = create_local_path(dir, res->path);
1035 1029
1036 char *link = SYNC_SYMLINK(dir) ? 1030 char *link = SYNC_SYMLINK(dir) ?
1037 dav_get_string_property_ns(res, DAV_PROPS_NS, "link") : NULL; 1031 dav_get_string_property_ns(res, DAV_PROPS_NS, "link") : NULL;
1038 1032
1079 if(!strcmp(local->hash, hash)) { 1073 if(!strcmp(local->hash, hash)) {
1080 // resource is already up-to-date on the client 1074 // resource is already up-to-date on the client
1081 nochange = TRUE; 1075 nochange = TRUE;
1082 } 1076 }
1083 } else if(local->etag) { 1077 } else if(local->etag) {
1084 sstr_t e = sstr(etag); 1078 cxstring e = cx_str(etag);
1085 if(sstrprefix(e, S("W/"))) { 1079 if(cx_strprefix(e, CX_STR("W/"))) {
1086 e = sstrsubs(e, 2); 1080 e = cx_strsubs(e, 2);
1087 } 1081 }
1088 if(!strcmp(e.ptr, local->etag)) { 1082 if(!strcmp(e.ptr, local->etag)) {
1089 // resource is already up-to-date on the client 1083 // resource is already up-to-date on the client
1090 nochange = TRUE; 1084 nochange = TRUE;
1091 } 1085 }
1162 // if a file is not modified, check if the metadata has changed 1156 // if a file is not modified, check if the metadata has changed
1163 while(ret == REMOTE_NO_CHANGE && local) { 1157 while(ret == REMOTE_NO_CHANGE && local) {
1164 // check if tags have changed 1158 // check if tags have changed
1165 if(dir->tagconfig) { 1159 if(dir->tagconfig) {
1166 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_PROPS_NS, "tags"); 1160 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_PROPS_NS, "tags");
1167 UcxList *remote_tags = NULL; 1161 CxList *remote_tags = NULL;
1168 if(tagsprop) { 1162 if(tagsprop) {
1169 remote_tags = parse_dav_xml_taglist(tagsprop); 1163 remote_tags = parse_dav_xml_taglist(tagsprop);
1170 } 1164 }
1171 char *remote_hash = create_tags_hash(remote_tags); 1165 char *remote_hash = create_tags_hash(remote_tags);
1172 if(nullstrcmp(remote_hash, local->remote_tags_hash)) { 1166 if(nullstrcmp(remote_hash, local->remote_tags_hash)) {
1211 if(ret == REMOTE_NO_CHANGE && update_db) { 1205 if(ret == REMOTE_NO_CHANGE && update_db) {
1212 if(!local) { 1206 if(!local) {
1213 local = calloc(1, sizeof(LocalResource)); 1207 local = calloc(1, sizeof(LocalResource));
1214 local->path = strdup(res->path); 1208 local->path = strdup(res->path);
1215 1209
1216 ucx_map_cstr_put(db->resources, local->path, local); 1210 cxMapPut(db->resources, cx_hash_key_str(local->path), local);
1217 } 1211 }
1218 1212
1219 // update local res 1213 // update local res
1220 SYS_STAT s; 1214 SYS_STAT s;
1221 if(!sys_stat(local_path, &s)) { 1215 if(!sys_stat(local_path, &s)) {
1243 local->uid = s->st_uid; 1237 local->uid = s->st_uid;
1244 local->gid = s->st_gid; 1238 local->gid = s->st_gid;
1245 local->size = s->st_size; 1239 local->size = s->st_size;
1246 } 1240 }
1247 1241
1248 static UcxList* sync_download_changed_parts( 1242 static CxList* sync_download_changed_parts(
1249 DavResource *res, 1243 DavResource *res,
1250 LocalResource *local, 1244 LocalResource *local,
1251 FILE *out, 1245 FILE *out,
1252 size_t blocksize, 1246 size_t blocksize,
1253 uint64_t *blockcount, 1247 uint64_t *blockcount,
1254 int64_t *truncate_file, 1248 int64_t *truncate_file,
1255 int *err) 1249 int *err)
1256 { 1250 {
1257 UcxList *updates = NULL; 1251 CxList *updates = cxLinkedListCreateSimple(CX_STORE_POINTERS);
1252 updates->simple_destructor = (cx_destructor_func)filepart_free;
1258 1253
1259 size_t local_numparts = local ? local->numparts : 0; 1254 size_t local_numparts = local ? local->numparts : 0;
1260 fseeko(out, 0, SEEK_END); 1255 fseeko(out, 0, SEEK_END);
1261 off_t end = ftello(out); 1256 off_t end = ftello(out);
1262 1257
1263 int error = 0; 1258 int error = 0;
1264 1259
1265 UcxBuffer *buf = ucx_buffer_new(NULL, blocksize, 0); 1260 CxBuffer *buf = cxBufferCreate(NULL, blocksize, cxDefaultAllocator, 0);
1266 1261
1267 int64_t maxsize = -1; 1262 int64_t maxsize = -1;
1268 1263
1269 DavResource *part = res->children; 1264 DavResource *part = res->children;
1270 uint64_t i = 0; 1265 uint64_t i = 0;
1304 fprintf(stderr, "Error: fseek failed: %s\n", strerror(errno)); 1299 fprintf(stderr, "Error: fseek failed: %s\n", strerror(errno));
1305 break; 1300 break;
1306 } 1301 }
1307 buf->pos = 0; 1302 buf->pos = 0;
1308 buf->size = 0; 1303 buf->size = 0;
1309 if(dav_get_content(part, buf,(dav_write_func)ucx_buffer_write)) { 1304 if(dav_get_content(part, buf,(dav_write_func)cxBufferWrite)) {
1310 fprintf(stderr, "Error: cannot download part: %s\n", part->name); 1305 fprintf(stderr, "Error: cannot download part: %s\n", part->name);
1311 error = 1; 1306 error = 1;
1312 break; 1307 break;
1313 } 1308 }
1314 if(fwrite(buf->space, 1, buf->size, out) == 0) { 1309 if(fwrite(buf->space, 1, buf->size, out) == 0) {
1319 1314
1320 FilePart *update = calloc(1, sizeof(FilePart)); 1315 FilePart *update = calloc(1, sizeof(FilePart));
1321 update->block = partnum; 1316 update->block = partnum;
1322 update->etag = etag ? strdup(etag) : NULL; 1317 update->etag = etag ? strdup(etag) : NULL;
1323 update->hash = dav_create_hash(buf->space, buf->size); 1318 update->hash = dav_create_hash(buf->space, buf->size);
1324 updates = ucx_list_append(updates, update); 1319 cxListAdd(updates, update);
1325 1320
1326 block_end = offset+buf->size; 1321 block_end = offset+buf->size;
1327 } else { 1322 } else {
1328 if(offset+blocksize > end) { 1323 if(offset+blocksize > end) {
1329 // if we don't download the block, we don't know the size 1324 // if we don't download the block, we don't know the size
1341 i++; 1336 i++;
1342 } // else: res is not a regular file part 1337 } // else: res is not a regular file part
1343 part = part->next; 1338 part = part->next;
1344 } 1339 }
1345 1340
1346 ucx_buffer_free(buf); 1341 cxBufferFree(buf);
1347 1342
1348 if(error) { 1343 if(error) {
1349 *err = 1; 1344 *err = 1;
1350 ucx_list_free_content(updates, (ucx_destructor)filepart_free); 1345 cxListDestroy(updates);
1351 return NULL; 1346 return NULL;
1352 } 1347 }
1353 1348
1354 if(maxsize < end) { 1349 if(maxsize < end) {
1355 *truncate_file = maxsize; 1350 *truncate_file = maxsize;
1371 if(!out) { 1366 if(!out) {
1372 fclose(in); 1367 fclose(in);
1373 return 1; 1368 return 1;
1374 } 1369 }
1375 1370
1376 ucx_stream_copy(in, out, (read_func)fread, (write_func)fwrite); 1371 cx_stream_copy(in, out, (cx_read_func)fread, (cx_write_func)fwrite);
1377 fclose(in); 1372 fclose(in);
1378 fclose(out); 1373 fclose(out);
1379 1374
1380 return 0; 1375 return 0;
1381 } 1376 }
1413 // with all metadata hashes 1408 // with all metadata hashes
1414 local = local_resource_copy(content, res->path); 1409 local = local_resource_copy(content, res->path);
1415 } else { 1410 } else {
1416 // reuse previous LocalResource (content) 1411 // reuse previous LocalResource (content)
1417 // remove it from db->resources, change path and put it back 1412 // remove it from db->resources, change path and put it back
1418 local = ucx_map_cstr_remove(db->resources, content->path); 1413 local = cxMapRemoveAndGet(db->resources, cx_hash_key_str(content->path));
1419 if(!local) { 1414 if(!local) {
1420 // can't happen, but handle it nevertheless 1415 // can't happen, but handle it nevertheless
1421 local = content; 1416 local = content;
1422 } 1417 }
1423 free(content->path); 1418 free(content->path);
1424 local->path = strdup(res->path); 1419 local->path = strdup(res->path);
1425 } 1420 }
1426 ucx_map_cstr_put(db->resources, local->path, local); 1421 cxMapPut(db->resources, cx_hash_key_str(local->path), local);
1427 1422
1428 if(sync_store_metadata(dir, new_path, local, res)) { 1423 if(sync_store_metadata(dir, new_path, local, res)) {
1429 fprintf(stderr, "Cannot store metadata: %s\n", res->path); 1424 fprintf(stderr, "Cannot store metadata: %s\n", res->path);
1430 } 1425 }
1431 1426
1461 int *counter) 1456 int *counter)
1462 { 1457 {
1463 char *link = SYNC_SYMLINK(dir) ? 1458 char *link = SYNC_SYMLINK(dir) ?
1464 dav_get_string_property_ns(res, DAV_PROPS_NS, "link") : NULL; 1459 dav_get_string_property_ns(res, DAV_PROPS_NS, "link") : NULL;
1465 1460
1466 LocalResource *local = ucx_map_cstr_get(db->resources, path); 1461 LocalResource *local = cxMapGet(db->resources, cx_hash_key_str(path));
1467 1462
1468 char *local_path; 1463 char *local_path;
1469 if(link) { 1464 if(link) {
1470 char *res_path = resource_local_path(res); 1465 char *res_path = resource_local_path(res);
1471 local_path = create_local_path(dir, res_path); 1466 local_path = create_local_path(dir, res_path);
1486 fprintf(stderr, "Error: split property does not contain an integer.\n"); 1481 fprintf(stderr, "Error: split property does not contain an integer.\n");
1487 return 1; 1482 return 1;
1488 } 1483 }
1489 issplit = TRUE; 1484 issplit = TRUE;
1490 } 1485 }
1491 UcxList *part_updates = NULL; 1486 CxList *part_updates = NULL;
1492 uint64_t blockcount = 0; 1487 uint64_t blockcount = 0;
1493 char *content_hash = NULL; 1488 char *content_hash = NULL;
1494 1489
1495 if(res->iscollection && !issplit) { 1490 if(res->iscollection && !issplit) {
1496 // why are we here? 1491 // why are we here?
1588 if(update_db && ret == 0) { 1583 if(update_db && ret == 0) {
1589 if(!local) { 1584 if(!local) {
1590 // new local resource 1585 // new local resource
1591 local = calloc(1, sizeof(LocalResource)); 1586 local = calloc(1, sizeof(LocalResource));
1592 local->path = strdup(path); 1587 local->path = strdup(path);
1593 ucx_map_cstr_put(db->resources, local->path, local); 1588 cxMapPut(db->resources, cx_hash_key_str(local->path), local);
1594 } 1589 }
1595 1590
1596 if(sync_store_metadata(dir, local_path, local, res)) { 1591 if(sync_store_metadata(dir, local_path, local, res)) {
1597 fprintf(stderr, "Cannot store metadata: %s\n", path); 1592 fprintf(stderr, "Cannot store metadata: %s\n", path);
1598 } 1593 }
1671 free(local_path); 1666 free(local_path);
1672 return 1; 1667 return 1;
1673 } 1668 }
1674 1669
1675 // if it doesn't exist in the db, create an entry for the dir 1670 // if it doesn't exist in the db, create an entry for the dir
1676 LocalResource *local = ucx_map_cstr_get(db->resources, res->path); 1671 LocalResource *local = cxMapGet(db->resources, cx_hash_key_str(res->path));
1677 if(!local) { 1672 if(!local) {
1678 local = calloc(1, sizeof(LocalResource)); 1673 local = calloc(1, sizeof(LocalResource));
1679 local->path = strdup(res->path); 1674 local->path = strdup(res->path);
1680 ucx_map_cstr_put(db->resources, local->path, local); 1675 cxMapPut(db->resources, cx_hash_key_str(local->path), local);
1681 } 1676 }
1682 local->isdirectory = 1; 1677 local->isdirectory = 1;
1683 1678
1684 // cleanup LocalResource 1679 // cleanup LocalResource
1685 if(local->etag) { 1680 if(local->etag) {
1768 int rev = 0; 1763 int rev = 0;
1769 SYS_STAT s; 1764 SYS_STAT s;
1770 int loop = 1; 1765 int loop = 1;
1771 do { 1766 do {
1772 char *res_parent = util_parent_path(path); 1767 char *res_parent = util_parent_path(path);
1773 char *res_name = util_resource_name(path); 1768 const char *res_name = util_resource_name(path);
1774 1769
1775 sstr_t new_path = ucx_sprintf( 1770 cxmutstr new_path = cx_asprintf(
1776 "%sorig.%d.%s", 1771 "%sorig.%d.%s",
1777 parent, 1772 parent,
1778 rev, 1773 rev,
1779 res_name); 1774 res_name);
1780 sstr_t new_res_path = ucx_sprintf( 1775 cxmutstr new_res_path = cx_asprintf(
1781 "%sorig.%d.%s", 1776 "%sorig.%d.%s",
1782 res_parent, 1777 res_parent,
1783 rev, 1778 rev,
1784 res_name); 1779 res_name);
1785 1780
1797 new_path.ptr); 1792 new_path.ptr);
1798 } else { 1793 } else {
1799 LocalResource *conflict = calloc(1, sizeof(LocalResource)); 1794 LocalResource *conflict = calloc(1, sizeof(LocalResource));
1800 conflict->path = strdup(new_res_path.ptr); 1795 conflict->path = strdup(new_res_path.ptr);
1801 conflict->conflict_source = strdup(path); 1796 conflict->conflict_source = strdup(path);
1802 ucx_map_cstr_put(db->conflict, new_res_path.ptr, conflict); 1797 cxMapPut(db->conflict, cx_hash_key_str(new_res_path.ptr), conflict);
1803 } 1798 }
1804 } 1799 }
1805 } 1800 }
1806 rev++; 1801 rev++;
1807 free(res_parent); 1802 free(res_parent);
1815 1810
1816 char* create_tmp_download_path(char *path) { 1811 char* create_tmp_download_path(char *path) {
1817 char *new_path = NULL; 1812 char *new_path = NULL;
1818 char *parent = util_parent_path(path); 1813 char *parent = util_parent_path(path);
1819 for (int i=0;;i++) { 1814 for (int i=0;;i++) {
1820 sstr_t np = ucx_asprintf( 1815 cxmutstr np = cx_asprintf(
1821 ucx_default_allocator(),
1822 "%sdownload%d-%s", 1816 "%sdownload%d-%s",
1823 parent, 1817 parent,
1824 i, 1818 i,
1825 util_resource_name(path)); 1819 util_resource_name(path));
1826 1820
1839 } 1833 }
1840 1834
1841 void move_to_trash(SyncDirectory *dir, char *path) { 1835 void move_to_trash(SyncDirectory *dir, char *path) {
1842 char *new_path = NULL; 1836 char *new_path = NULL;
1843 for (int i=0;;i++) { 1837 for (int i=0;;i++) {
1844 sstr_t np = ucx_asprintf( 1838 cxmutstr np = cx_asprintf(
1845 ucx_default_allocator(),
1846 "%s%d-%s", 1839 "%s%d-%s",
1847 dir->trash, 1840 dir->trash,
1848 i, 1841 i,
1849 util_resource_name(path)); 1842 util_resource_name(path));
1850 1843
1874 1867
1875 free(new_path); 1868 free(new_path);
1876 } 1869 }
1877 1870
1878 static int res_isconflict(SyncDatabase *db, LocalResource *res) { 1871 static int res_isconflict(SyncDatabase *db, LocalResource *res) {
1879 return ucx_map_cstr_get(db->conflict, res->path) ? 1 : 0; 1872 return cxMapGet(db->conflict, cx_hash_key_str(res->path)) ? 1 : 0;
1880 } 1873 }
1881 1874
1882 int cmd_push(CmdArgs *a, DavBool outgoing, DavBool archive) { 1875 int cmd_push(CmdArgs *a, DavBool outgoing, DavBool archive) {
1883 if(a->argc != 1) { 1876 if(a->argc != 1) {
1884 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many"); 1877 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many");
1915 fprintf(stderr, "Command '%s' is not allowed for this sync dir\n", archive ? "archive" : "push"); 1908 fprintf(stderr, "Command '%s' is not allowed for this sync dir\n", archive ? "archive" : "push");
1916 print_allowed_cmds(dir); 1909 print_allowed_cmds(dir);
1917 return -1; 1910 return -1;
1918 } 1911 }
1919 1912
1920 Repository *repo = get_repository(sstr(dir->repository)); 1913 Repository *repo = get_repository(cx_str(dir->repository));
1921 if(!repo) { 1914 if(!repo) {
1922 fprintf(stderr, "Unkown repository %s\n", dir->name); 1915 fprintf(stderr, "Unkown repository %s\n", dir->name);
1923 return -1; 1916 return -1;
1924 } 1917 }
1925 1918
1929 return -1; 1922 return -1;
1930 } 1923 }
1931 remove_deleted_conflicts(dir, db); 1924 remove_deleted_conflicts(dir, db);
1932 1925
1933 DavSession *sn = create_session(a, ctx, repo, dir->collection); 1926 DavSession *sn = create_session(a, ctx, repo, dir->collection);
1934 ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db); 1927 util_regdestr(sn->mp, db, (cx_destructor_func)destroy_db);
1935 if (cmd_getoption(a, "verbose")) { 1928 if (cmd_getoption(a, "verbose")) {
1936 curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L); 1929 curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L);
1937 curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr); 1930 curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr);
1938 } 1931 }
1939 if(SYNC_STORE_HASH(dir)) { 1932 if(SYNC_STORE_HASH(dir)) {
1951 dav_session_destroy(sn); 1944 dav_session_destroy(sn);
1952 fprintf(stderr, "Abort\n"); 1945 fprintf(stderr, "Abort\n");
1953 return -1; 1946 return -1;
1954 } 1947 }
1955 1948
1956 UcxMap *svrres = NULL; 1949 CxMap *svrres = NULL;
1957 if(restore) { 1950 if(restore) {
1958 svrres = ucx_map_new(1024); 1951 svrres = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 1024);
1959 res2map(root, svrres); 1952 res2map(root, svrres);
1960 } 1953 }
1961 1954
1962 int cdt = cmd_getoption(a, "conflict") ? 0 : 1; // conflict detection 1955 int cdt = cmd_getoption(a, "conflict") ? 0 : 1; // conflict detection
1963 1956
1979 locktokenfile = create_locktoken_file(dir->name, lock->token); 1972 locktokenfile = create_locktoken_file(dir->name, lock->token);
1980 } 1973 }
1981 1974
1982 DavBool remove_file = cmd_getoption(a, "remove") ? 1 : 0; 1975 DavBool remove_file = cmd_getoption(a, "remove") ? 1 : 0;
1983 1976
1984 UcxMap *db_hashes = NULL; 1977 CxMap *db_hashes = NULL;
1985 if(SYNC_HASHING(dir)) { 1978 if(SYNC_HASHING(dir)) {
1986 db_hashes = create_hash_index(db); 1979 db_hashes = create_hash_index(db);
1987 } 1980 }
1988 1981
1989 int sync_success = 0; 1982 int sync_success = 0;
1990 int sync_delete = 0; 1983 int sync_delete = 0;
1991 int sync_conflict = 0; 1984 int sync_conflict = 0;
1992 int sync_error = 0; 1985 int sync_error = 0;
1993 1986
1994 UcxList *ls_new = NULL; 1987 CxList *ls_new = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
1995 UcxList *ls_modified = NULL; 1988 CxList *ls_modified = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
1996 UcxList *ls_conflict = NULL; 1989 CxList *ls_conflict = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
1997 UcxList *ls_update = NULL; 1990 CxList *ls_update = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
1998 UcxList *ls_delete = NULL; 1991 CxList *ls_delete = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
1999 UcxList *ls_move = NULL; 1992 CxList *ls_move = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
2000 UcxList *ls_copy = NULL; 1993 CxList *ls_copy = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
2001 UcxList *ls_mkcol = NULL; 1994 CxList *ls_mkcol = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)resource_path_cmp, CX_STORE_POINTERS);
1995
2002 1996
2003 // upload all changed files 1997 // upload all changed files
2004 //UcxList *resources = cmd_getoption(a, "read") ? 1998 //UcxList *resources = cmd_getoption(a, "read") ?
2005 // read_changes(dir, db) : local_scan(dir, db); 1999 // read_changes(dir, db) : local_scan(dir, db);
2006 UcxList *resources = local_scan(dir, db); 2000 CxList *resources = local_scan(dir, db);
2007 UcxMap *resources_map = ucx_map_new(ucx_list_size(resources)+16); 2001 CxMap *resources_map = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, resources->size+16);
2008 2002
2009 UCX_FOREACH(elm, resources) { 2003 CxIterator iter = cxListIterator(resources);
2010 LocalResource *local_res = elm->data; 2004 cx_foreach(LocalResource *, local_res, iter) {
2011 // ignore all files, that are excluded by a static filter (sync.xml) 2005 // ignore all files, that are excluded by a static filter (sync.xml)
2012 2006
2013 // static include/exclude filter 2007 // static include/exclude filter
2014 if(res_matches_dir_filter(dir, local_res->path+1)) { 2008 if(res_matches_dir_filter(dir, local_res->path+1)) {
2015 continue; 2009 continue;
2016 } 2010 }
2017 // static tag filter 2011 // static tag filter
2018 UCX_FOREACH(elm, dir->filter.tags) { 2012 if(dir->filter.tags) {
2019 SyncTagFilter *tf = elm->data; 2013 CxIterator tag_iter = cxListIterator(dir->filter.tags);
2020 if(!localres_matches_tags(dir, local_res, tf)) { 2014 cx_foreach(SyncTagFilter *, tf, tag_iter) {
2021 continue; 2015 if(!localres_matches_tags(dir, local_res, tf)) {
2022 } 2016 continue;
2023 } 2017 }
2018 }
2019 }
2020
2024 2021
2025 // we need a fast file lookup map later to detect deleted files 2022 // we need a fast file lookup map later to detect deleted files
2026 ucx_map_cstr_put(resources_map, local_res->path, local_res); 2023 cxMapPut(resources_map, cx_hash_key_str(local_res->path), local_res);
2027 2024
2028 // dynamic tag filter 2025 // dynamic tag filter
2029 if(!localres_matches_tags(dir, local_res, tagfilter)) { 2026 if(!localres_matches_tags(dir, local_res, tagfilter)) {
2030 if(!remove_file) { 2027 if(!remove_file) {
2031 LocalResource *dbres = ucx_map_cstr_get( 2028 LocalResource *dbres = cxMapGet(
2032 db->resources, 2029 db->resources,
2033 local_res->path); 2030 cx_hash_key_str(local_res->path));
2034 if(dbres) { 2031 if(dbres) {
2035 // this makes sure the file will not be deleted later 2032 // this makes sure the file will not be deleted later
2036 dbres->keep = TRUE; 2033 dbres->keep = TRUE;
2037 } 2034 }
2038 } 2035 }
2039 continue; 2036 continue;
2040 } 2037 }
2041 2038
2042 // skip conflict backups silently 2039 // skip conflict backups silently
2043 if(res_isconflict(db, local_res)) { 2040 if(res_isconflict(db, local_res)) {
2044 ls_conflict = ucx_list_append(ls_conflict, local_res); 2041 cxListAdd(ls_conflict, local_res);
2045 continue; 2042 continue;
2046 } 2043 }
2047 2044
2048 int is_changed = local_resource_is_changed( 2045 int is_changed = local_resource_is_changed(
2049 dir, 2046 dir,
2052 svrres, 2049 svrres,
2053 restore_removed, 2050 restore_removed,
2054 restore_modified); 2051 restore_modified);
2055 if(is_changed) { 2052 if(is_changed) {
2056 if(local_res->isdirectory) { 2053 if(local_res->isdirectory) {
2057 ls_mkcol = ucx_list_append(ls_mkcol, local_res); 2054 cxListAdd(ls_mkcol, local_res);
2058 } else if(local_res->isnew) { 2055 } else if(local_res->isnew) {
2059 ls_new = ucx_list_append(ls_new, local_res); 2056 cxListAdd(ls_new, local_res);
2060 } else { 2057 } else {
2061 ls_modified = ucx_list_append(ls_modified, local_res); 2058 cxListAdd(ls_modified, local_res);
2062 } 2059 }
2063 } else if(local_res->metadata_updated) { 2060 } else if(local_res->metadata_updated) {
2064 ls_update = ucx_list_append(ls_update, local_res); 2061 cxListAdd(ls_update, local_res);
2065 } 2062 }
2066 2063
2067 if(local_res->isnew) { 2064 if(local_res->isnew) {
2068 if(local_resource_load_metadata(dir, local_res)) { 2065 if(local_resource_load_metadata(dir, local_res)) {
2069 fprintf( 2066 fprintf(
2075 } 2072 }
2076 2073
2077 if(SYNC_STORE_HASH(dir)) { 2074 if(SYNC_STORE_HASH(dir)) {
2078 // calculate hashes of all new files and check if a file 2075 // calculate hashes of all new files and check if a file
2079 // was moved or is a copy 2076 // was moved or is a copy
2080 UcxList *elm = ls_new; 2077 CxMutIterator mut_iter = cxListMutIterator(ls_new);
2081 while(elm) { 2078 cx_foreach(LocalResource *, local, mut_iter) {
2082 LocalResource *local = elm->data;
2083 UcxList *prev = elm->prev;
2084 UcxList *next = elm->next;
2085 if(local->isdirectory || local->link_target) { 2079 if(local->isdirectory || local->link_target) {
2086 elm = elm->next;
2087 continue; 2080 continue;
2088 } 2081 }
2089 2082
2090 char *local_path = util_concat_path(dir->path, local_resource_path(local)); 2083 char *local_path = util_concat_path(dir->path, local_resource_path(local));
2091 char *hash = util_file_hash(local_path); 2084 char *hash = util_file_hash(local_path);
2092 local->hash = hash; 2085 local->hash = hash;
2093 // check if a file with this hash already exists 2086 // check if a file with this hash already exists
2094 LocalResource *origin = ucx_map_cstr_get(db_hashes, hash); 2087 LocalResource *origin = cxMapGet(db_hashes, cx_hash_key_str(hash));
2095 if(origin) { 2088 if(origin) {
2096 local->origin = local_resource_copy(origin, origin->path); 2089 local->origin = local_resource_copy(origin, origin->path);
2097 // the file is a copied/moved file 2090 // the file is a copied/moved file
2098 // check if the file is in the resources_map, because then 2091 // check if the file is in the resources_map, because then
2099 // it still exists 2092 // it still exists
2100 if(ucx_map_cstr_get(resources_map, origin->path)) { 2093 if(cxMapGet(resources_map, cx_hash_key_str(origin->path))) {
2101 ls_copy = ucx_list_append(ls_copy, local); 2094 cxListAdd(ls_copy, local);
2102 } else { 2095 } else {
2103 ls_move = ucx_list_append(ls_move, local); 2096 cxListAdd(ls_move, local);
2104 // put file in resources_map to prevent deletion 2097 // put file in resources_map to prevent deletion
2105 ucx_map_cstr_put(resources_map, origin->path, local); 2098 cxMapPut(resources_map, cx_hash_key_str(origin->path), local);
2106 } 2099 }
2107 // remove list elemend from ls_new 2100 // remove list elemend from ls_new
2108 if(prev) { 2101 cxIteratorFlagRemoval(mut_iter);
2109 prev->next = next;
2110 } else {
2111 ls_new = next;
2112 }
2113 if(next) {
2114 next->prev = prev;
2115 }
2116 } 2102 }
2117 2103
2118 free(local_path); 2104 free(local_path);
2119
2120 elm = next;
2121 } 2105 }
2122 } 2106 }
2123 2107
2124 // find all deleted files and cleanup the database 2108 // find all deleted files and cleanup the database
2125 UcxMapIterator i = ucx_map_iterator(db->resources); 2109 iter = cxMapIterator(db->resources);
2126 LocalResource *local; 2110 LocalResource *local;
2127 UcxList *removed_res = NULL; 2111 CxList *removed_res = cxLinkedListCreateSimple(CX_STORE_POINTERS);
2128 UCX_MAP_FOREACH(key, local, i) { 2112 cx_foreach(CxMapEntry *, entry, iter) {
2113 LocalResource *local = entry->value;
2129 // all filtered files should be removed from the database 2114 // all filtered files should be removed from the database
2130 if(res_matches_dir_filter(dir, local->path+1)) { 2115 if(res_matches_dir_filter(dir, local->path+1)) {
2131 ucx_map_cstr_remove(db->resources, local->path); 2116 cxMapRemove(db->resources, local->path);
2132 continue; 2117 continue;
2133 } 2118 }
2134 UCX_FOREACH(elm, dir->filter.tags) { 2119 CxIterator tag_iter = cxListIterator(dir->filter.tags);
2135 SyncTagFilter *tf = elm->data; 2120 cx_foreach(SyncTagFilter *, tf, tag_iter) {
2136 if(!localres_matches_tags(dir, local, tf)) { 2121 if(!localres_matches_tags(dir, local, tf)) {
2137 ucx_map_cstr_remove(db->resources, local->path); 2122 cxMapRemove(db->resources, local->path);
2138 continue; 2123 continue;
2139 } 2124 }
2140 } 2125 }
2141 2126
2142 if(!ucx_map_get(resources_map, key)) { 2127 if(!cxMapGet(resources_map, *entry->key)) {
2143 // The current LocalResource is in the database but doesn't exist 2128 // The current LocalResource is in the database but doesn't exist
2144 // in the filesystem anymore. This means the file was deleted 2129 // in the filesystem anymore. This means the file was deleted
2145 // and should be deleted on the server 2130 // and should be deleted on the server
2146 if(!archive) { 2131 if(!archive) {
2147 ls_delete = ucx_list_append(ls_delete, local); 2132 cxListAdd(ls_delete, local);
2148 } else { 2133 } else {
2149 removed_res = ucx_list_prepend(removed_res, local); 2134 cxListInsert(removed_res, 0, local);
2150 } 2135 }
2151 } 2136 }
2152 } 2137 }
2153 UCX_FOREACH(elm, removed_res) { 2138 iter = cxListIterator(removed_res);
2154 LocalResource *local = elm->data; 2139 cx_foreach(LocalResource *, local, iter) {
2155 ucx_map_cstr_remove(db->resources, local->path); 2140 cxMapRemove(db->resources, local->path);
2156 } 2141 }
2157 2142
2158 ls_new = ucx_list_sort(ls_new, (cmp_func)resource_path_cmp, NULL); 2143 cxListSort(ls_new);
2159 ls_modified = ucx_list_sort(ls_modified, (cmp_func)resource_path_cmp, NULL); 2144 cxListSort(ls_modified);
2160 ls_conflict = ucx_list_sort(ls_conflict, (cmp_func)resource_path_cmp, NULL); 2145 cxListSort(ls_conflict);
2161 ls_update = ucx_list_sort(ls_update, (cmp_func)resource_path_cmp, NULL); 2146 cxListSort(ls_update);
2162 ls_delete = ucx_list_sort(ls_delete, (cmp_func)resource_path_cmp, NULL); 2147 cxListSort(ls_delete);
2163 ls_move = ucx_list_sort(ls_move, (cmp_func)resource_path_cmp, NULL); 2148 cxListSort(ls_move);
2164 ls_copy = ucx_list_sort(ls_copy, (cmp_func)resource_path_cmp, NULL); 2149 cxListSort(ls_copy);
2165 ls_mkcol = ucx_list_sort(ls_mkcol, (cmp_func)resource_path_cmp, NULL); 2150 cxListSort(ls_mkcol);
2166 2151
2167 if(outgoing) { 2152 if(outgoing) {
2168 print_outgoing( 2153 print_outgoing(
2169 a, 2154 a,
2170 ls_new, 2155 ls_new,
2184 2169
2185 int ret = 0; 2170 int ret = 0;
2186 int error = 0; 2171 int error = 0;
2187 2172
2188 // create collections 2173 // create collections
2189 for(UcxList *elm=ls_mkcol;elm && !sync_shutdown;elm=elm->next) { 2174 iter = cxListIterator(ls_mkcol);
2190 LocalResource *local_res = elm->data; 2175 cx_foreach(LocalResource *, local_res, iter) {
2176 if(sync_shutdown) {
2177 break;
2178 }
2191 2179
2192 DavResource *res = dav_resource_new(sn, local_res->path); 2180 DavResource *res = dav_resource_new(sn, local_res->path);
2193 if(!res) { 2181 if(!res) {
2194 print_resource_error(sn, local_res->path); 2182 print_resource_error(sn, local_res->path);
2195 ret = -1; 2183 ret = -1;
2225 sync_update_metadata(dir, sn, res, local_res); 2213 sync_update_metadata(dir, sn, res, local_res);
2226 } 2214 }
2227 2215
2228 // remove old db entry (if it exists) 2216 // remove old db entry (if it exists)
2229 // and add add new entry 2217 // and add add new entry
2230 LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path); 2218 // TODO: free??
2231 ucx_map_cstr_put(db->resources, local_res->path, local_res); 2219 LocalResource *dbres = cxMapGet(db->resources, cx_hash_key_str(local_res->path));
2220 cxMapPut(db->resources, cx_hash_key_str(local_res->path), local_res);
2232 } 2221 }
2233 2222
2234 dav_resource_free(res); 2223 dav_resource_free(res);
2235 } 2224 }
2236 2225
2238 DavBool copy = TRUE; 2227 DavBool copy = TRUE;
2239 if(!ls_copy) { 2228 if(!ls_copy) {
2240 copy = FALSE; 2229 copy = FALSE;
2241 ls_copy = ls_move; 2230 ls_copy = ls_move;
2242 } 2231 }
2243 for(UcxList *elm=ls_copy;elm && !sync_shutdown;elm=elm->next) { 2232 iter = cxListIterator(ls_copy);
2244 LocalResource *local = elm->data; 2233 for(int i=0;i<2;i++) {
2245 2234 cx_foreach(LocalResource*, local, iter) {
2246 int err = 0; 2235 if(sync_shutdown) {
2247 DavResource *res = dav_resource_new(sn, local->path); 2236 break;
2248 if(dav_exists(res)) { 2237 }
2249 printf("conflict: %s\n", local->path); 2238
2250 local->last_modified = 0; 2239 int err = 0;
2251 nullfree(local->etag); 2240 DavResource *res = dav_resource_new(sn, local->path);
2252 local->etag = NULL; 2241 if(dav_exists(res)) {
2253 nullfree(local->hash); 2242 printf("conflict: %s\n", local->path);
2254 local->hash = NULL; 2243 local->last_modified = 0;
2255 local->skipped = TRUE; 2244 nullfree(local->etag);
2256 sync_conflict++; 2245 local->etag = NULL;
2257 } else { 2246 nullfree(local->hash);
2258 DavResource *origin_res = dav_resource_new(sn, local->origin->path); 2247 local->hash = NULL;
2259 int origin_changed = remote_resource_is_changed( 2248 local->skipped = TRUE;
2260 sn, 2249 sync_conflict++;
2261 dir,
2262 db,
2263 origin_res,
2264 local->origin,
2265 NULL);
2266 if(origin_changed) {
2267 // upload with put
2268 ls_modified = ucx_list_prepend(ls_modified, local);
2269 } else { 2250 } else {
2270 printf("%s: %s -> %s\n", copy ? "copy":"move", local->origin->path, local->path); 2251 DavResource *origin_res = dav_resource_new(sn, local->origin->path);
2271 err = sync_move_remote_resource( 2252 int origin_changed = remote_resource_is_changed(
2253 sn,
2272 dir, 2254 dir,
2273 db, 2255 db,
2274 origin_res, 2256 origin_res,
2275 local, 2257 local->origin,
2276 copy, 2258 NULL);
2277 &sync_success); 2259 if(origin_changed) {
2278 } 2260 // upload with put
2279 } 2261 cxListInsert(ls_modified, 0, local);
2280 2262 } else {
2281 if(err) { 2263 printf("%s: %s -> %s\n", copy ? "copy":"move", local->origin->path, local->path);
2282 sync_error++; 2264 err = sync_move_remote_resource(
2283 print_resource_error(sn, res->path); 2265 dir,
2284 ret = -1; 2266 db,
2285 error = 1; 2267 origin_res,
2286 } else { 2268 local,
2287 LocalResource *dbres = ucx_map_cstr_remove(db->resources, local->path); 2269 copy,
2288 ucx_map_cstr_put(db->resources, local->path, local); 2270 &sync_success);
2289 } 2271 }
2290 2272 }
2291 if(copy && !elm->next) { 2273
2292 // finished copy, begin move 2274 if(err) {
2293 elm->next = ls_move; 2275 sync_error++;
2294 copy = FALSE; 2276 print_resource_error(sn, res->path);
2295 } 2277 ret = -1;
2278 error = 1;
2279 } else {
2280 LocalResource *dbres = cxMapGet(db->resources, cx_hash_key_str(local->path));
2281 cxMapPut(db->resources, cx_hash_key_str(local->path), local);
2282 }
2283 }
2284 copy = FALSE;
2285 iter = cxListIterator(ls_move);
2296 } 2286 }
2297 2287
2298 // upload changed files 2288 // upload changed files
2299 ls_modified = ucx_list_concat(ls_new, ls_modified); 2289 //ls_modified = ucx_list_concat(ls_new, ls_modified);
2300 2290 iter = cxListIterator(ls_new);
2301 for(UcxList *elm=ls_modified;elm && !sync_shutdown;elm=elm->next) { 2291 for(int i=0;i<2;i++) {
2302 LocalResource *local_res = elm->data; 2292 cx_foreach(LocalResource*, local_res, iter) {
2303 int err = 0; 2293 if(sync_shutdown) {
2304 2294 break;
2305 DavResource *res = dav_resource_new(sn, local_res->path); 2295 }
2306 if(!res) { 2296
2307 print_resource_error(sn, local_res->path); 2297 int err = 0;
2308 ret = -1; 2298
2309 sync_error++; 2299 DavResource *res = dav_resource_new(sn, local_res->path);
2310 } else { 2300 if(!res) {
2311 DavBool equal = FALSE; 2301 print_resource_error(sn, local_res->path);
2312 DavBool res_conflict = FALSE; 2302 ret = -1;
2313 int changed = remote_resource_is_changed(sn, dir, db, res, local_res, &equal); 2303 sync_error++;
2314 if(equal) { 2304 } else {
2315 char *etag = dav_get_string_property(res, "D:getetag"); 2305 DavBool equal = FALSE;
2316 if(local_res->metadata_updated) { 2306 DavBool res_conflict = FALSE;
2317 ls_update = ucx_list_prepend(ls_update, local_res); 2307 int changed = remote_resource_is_changed(sn, dir, db, res, local_res, &equal);
2318 } else if(etag) { 2308 if(equal) {
2319 // update etag in db 2309 char *etag = dav_get_string_property(res, "D:getetag");
2320 if(local_res->etag) { 2310 if(local_res->metadata_updated) {
2321 free(local_res->etag); 2311 cxListInsert(ls_update, 0, local_res);
2312 } else if(etag) {
2313 // update etag in db
2314 if(local_res->etag) {
2315 free(local_res->etag);
2316 }
2317 local_res->etag = strdup(etag);
2322 } 2318 }
2323 local_res->etag = strdup(etag); 2319 } else if(cdt && changed) {
2324 } 2320 printf("conflict: %s\n", local_res->path);
2325 } else if(cdt && changed) { 2321 local_res->last_modified = 0;
2326 printf("conflict: %s\n", local_res->path); 2322 nullfree(local_res->etag);
2327 local_res->last_modified = 0; 2323 local_res->etag = NULL;
2328 nullfree(local_res->etag); 2324 nullfree(local_res->hash);
2329 local_res->etag = NULL; 2325 local_res->hash = NULL;
2330 nullfree(local_res->hash); 2326 local_res->skipped = TRUE;
2331 local_res->hash = NULL; 2327 sync_conflict++;
2332 local_res->skipped = TRUE; 2328
2333 sync_conflict++; 2329 if(local_res->link_target) {
2334 2330 free(local_res->link_target);
2335 if(local_res->link_target) { 2331 local_res->link_target = local_res->link_target_db;
2336 free(local_res->link_target); 2332 local_res->link_target_db = NULL;
2337 local_res->link_target = local_res->link_target_db; 2333 }
2338 local_res->link_target_db = NULL; 2334
2339 } 2335 res_conflict = TRUE;
2340
2341 res_conflict = TRUE;
2342 } else {
2343 if(local_res->link_target) {
2344 printf(
2345 "link: %s -> %s\n",
2346 local_res->path,
2347 local_res->link_target);
2348 } else { 2336 } else {
2349 printf("put: %s\n", local_res->path); 2337 if(local_res->link_target) {
2350 } 2338 printf(
2351 if(sync_put_resource(dir, res, local_res, &sync_success)) { 2339 "link: %s -> %s\n",
2352 sync_error++; 2340 local_res->path,
2353 print_resource_error(sn, res->path); 2341 local_res->link_target);
2354 ret = -1; 2342 } else {
2355 error = 1; 2343 printf("put: %s\n", local_res->path);
2356 2344 }
2357 err = 1; 2345 if(sync_put_resource(dir, res, local_res, &sync_success)) {
2358 } 2346 sync_error++;
2359 } 2347 print_resource_error(sn, res->path);
2360 2348 ret = -1;
2361 if(!err) { 2349 error = 1;
2362 LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path); 2350
2363 // in case of a conflict, don't store the resource 2351 err = 1;
2364 // in the db, if it is new 2352 }
2365 if(!res_conflict || dbres) { 2353 }
2366 ucx_map_cstr_put(db->resources, local_res->path, local_res); 2354
2367 } 2355 if(!err) {
2368 } 2356 LocalResource *dbres = cxMapRemoveAndGet(db->resources, cx_hash_key_str(local_res->path));
2369 } 2357 // in case of a conflict, don't store the resource
2370 2358 // in the db, if it is new
2371 dav_resource_free(res); 2359 if(!res_conflict || dbres) {
2360 cxMapPut(db->resources, cx_hash_key_str(local_res->path), local_res);
2361 }
2362 }
2363 }
2364
2365 dav_resource_free(res);
2366 }
2367 iter = cxListIterator(ls_modified);
2372 } 2368 }
2373 2369
2374 // metadata updates 2370 // metadata updates
2375 for(UcxList *elm=ls_update;elm && !sync_shutdown;elm=elm->next) { 2371 iter = cxListIterator(ls_update);
2376 LocalResource *local_res = elm->data; 2372 cx_foreach(LocalResource *, local_res, iter) {
2373 if(sync_shutdown) {
2374 break;
2375 }
2377 2376
2378 DavResource *res = dav_resource_new(sn, local_res->path); 2377 DavResource *res = dav_resource_new(sn, local_res->path);
2379 if(local_res->metadata_updated) { 2378 if(local_res->metadata_updated) {
2380 printf("update: %s\n", local_res->path); 2379 printf("update: %s\n", local_res->path);
2381 if(!sync_update_metadata(dir, sn, res, local_res)) { 2380 if(!sync_update_metadata(dir, sn, res, local_res)) {
2382 LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path); 2381 LocalResource *dbres = cxMapGet(db->resources, cx_hash_key_str(local_res->path));
2383 ucx_map_cstr_put(db->resources, local_res->path, local_res); 2382 cxMapPut(db->resources, cx_hash_key_str(local_res->path), local_res);
2384 } 2383 }
2385 } 2384 }
2386 } 2385 }
2387 2386
2388 // delete all removed files 2387 // delete all removed files
2389 ls_delete = ucx_list_sort(ls_delete, (cmp_func)resource_pathlen_cmp, NULL); 2388 cxListSort(ls_delete);
2390 2389
2391 UcxList *cols = NULL; 2390 CxList *cols = cxLinkedListCreateSimple(CX_STORE_POINTERS);
2392 UcxList **col_list = &cols; 2391 CxList *col_list = cols;
2393 UcxList *deletelist = ls_delete; 2392 CxList *deletelist = ls_delete;
2394 for(int i=0;i<2;i++) { 2393 for(int i=0;i<2;i++) {
2395 // the first iteration deletes everything from ls_delete except 2394 // the first iteration deletes everything from ls_delete except
2396 // all collections, which are stored in cols 2395 // all collections, which are stored in cols
2397 // in the second run all collections will be deleted 2396 // in the second run all collections will be deleted
2398 for(UcxList *elm=deletelist;elm && !sync_shutdown;elm=elm->next) { 2397 iter = cxListIterator(deletelist);
2399 LocalResource *local = elm->data; 2398 cx_foreach(LocalResource *, local, iter) {
2399 if(sync_shutdown) {
2400 break;
2401 }
2400 if(local->keep) { 2402 if(local->keep) {
2401 continue; 2403 continue;
2402 } 2404 }
2403 if(sync_delete_remote_resource(dir, sn, local, &sync_delete, col_list)) { 2405 if(sync_delete_remote_resource(dir, sn, local, &sync_delete, col_list)) {
2404 if(sn->error != DAV_NOT_FOUND) { 2406 if(sn->error != DAV_NOT_FOUND) {
2405 print_resource_error(sn, local->path); 2407 print_resource_error(sn, local->path);
2406 sync_error++; 2408 sync_error++;
2407 break; 2409 break;
2408 } 2410 }
2409 } else { 2411 } else {
2410 LocalResource *dbres = ucx_map_cstr_remove(db->resources, local->path); 2412 LocalResource *dbres = cxMapRemoveAndGet(db->resources, cx_hash_key_str(local->path));
2411 //local_resource_free(dbres); 2413 //local_resource_free(dbres);
2412 } 2414 }
2413 } 2415 }
2414 deletelist = cols; 2416 deletelist = cols;
2415 col_list = NULL; 2417 col_list = NULL;
2475 return -1; 2477 return -1;
2476 } 2478 }
2477 } 2479 }
2478 2480
2479 SyncDirectory *dir = NULL; 2481 SyncDirectory *dir = NULL;
2480 UcxMap *files = NULL; 2482 CxMap *files = NULL;
2481 if(syncdir) { 2483 if(syncdir) {
2482 dir = scfg_get_dir(syncdir); 2484 dir = scfg_get_dir(syncdir);
2483 } 2485 }
2484 2486
2485 LocalResource nres; 2487 LocalResource nres;
2486 if(a->argc > 0) { 2488 if(a->argc > 0) {
2487 files = ucx_map_new(a->argc+8); 2489 files = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, a->argc+8);
2488 // get all specified files and check the syncdir 2490 // get all specified files and check the syncdir
2489 SyncDirectory *sd = NULL; 2491 SyncDirectory *sd = NULL;
2490 for(int i=0;i<a->argc;i++) { 2492 for(int i=0;i<a->argc;i++) {
2491 SyncFile f; 2493 SyncFile f;
2492 int err = sync_get_file(a, a->argv[i], &f, FALSE); 2494 int err = sync_get_file(a, a->argv[i], &f, FALSE);
2501 fprintf(stderr, "Not all files are in the same syncdir\n"); 2503 fprintf(stderr, "Not all files are in the same syncdir\n");
2502 return 1; 2504 return 1;
2503 } 2505 }
2504 } 2506 }
2505 2507
2506 ucx_map_cstr_put(files, f.path, &nres); 2508 cxMapPut(files, cx_hash_key_str(f.path), &nres);
2507 } 2509 }
2508 dir = sd; 2510 dir = sd;
2509 } 2511 }
2510 2512
2511 if(!dir) { 2513 if(!dir) {
2534 fprintf(stderr, "Cannot load database file: %s\n", dir->database); 2536 fprintf(stderr, "Cannot load database file: %s\n", dir->database);
2535 return -1; 2537 return -1;
2536 } 2538 }
2537 remove_deleted_conflicts(dir, db); 2539 remove_deleted_conflicts(dir, db);
2538 2540
2539 UcxList *modified = NULL; 2541 CxList *modified = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)localres_cmp_path, CX_STORE_POINTERS);
2540 UcxList *deleted = NULL; 2542 CxList *deleted = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)localres_cmp_path, CX_STORE_POINTERS);
2541 2543
2542 // iterate over all db resources and check if any resource is 2544 // iterate over all db resources and check if any resource is
2543 // modified or deleted 2545 // modified or deleted
2544 UcxMapIterator i = ucx_map_iterator(files ? files : db->resources); 2546 CxIterator i = cxMapIterator(files ? files : db->resources);
2545 LocalResource *resource; 2547 cx_foreach(CxMapEntry *, entry, i) {
2546 UCX_MAP_FOREACH(key, resource, i) { 2548 LocalResource *resource = entry->value;
2547 if(resource == &nres) { 2549 if(resource == &nres) {
2548 resource = ucx_map_get(db->resources, key); 2550 resource = cxMapGet(db->resources, *entry->key);
2549 if(!resource) { 2551 if(!resource) {
2550 continue; 2552 continue;
2551 } 2553 }
2552 } 2554 }
2553 2555
2554 char *file_path = create_local_path(dir, resource->path); 2556 char *file_path = create_local_path(dir, resource->path);
2555 SYS_STAT s; 2557 SYS_STAT s;
2556 if(sys_stat(file_path, &s)) { 2558 if(sys_stat(file_path, &s)) {
2557 if(errno == ENOENT) { 2559 if(errno == ENOENT) {
2558 if(restore_removed) { 2560 if(restore_removed) {
2559 deleted = ucx_list_prepend(deleted, resource); 2561 cxListAdd(deleted, resource);
2560 } 2562 }
2561 } else { 2563 } else {
2562 fprintf(stderr, "Cannot stat file: %s\n", file_path); 2564 fprintf(stderr, "Cannot stat file: %s\n", file_path);
2563 perror(""); 2565 perror("");
2564 } 2566 }
2565 } else { 2567 } else {
2566 if(files) { 2568 if(files) {
2567 modified = ucx_list_prepend(modified, resource); 2569 cxListAdd(modified, resource);
2568 } else if(!resource->isdirectory && !S_ISDIR(s.st_mode)) { 2570 } else if(!resource->isdirectory && !S_ISDIR(s.st_mode)) {
2569 if(resource->last_modified != s.st_mtime || resource->size != s.st_size) { 2571 if(resource->last_modified != s.st_mtime || resource->size != s.st_size) {
2570 if(restore_modified) { 2572 if(restore_modified) {
2571 modified = ucx_list_prepend(modified, resource); 2573 cxListAdd(modified, resource);
2572 } 2574 }
2573 } 2575 }
2574 } 2576 }
2575 } 2577 }
2576 2578
2577 free(file_path); 2579 free(file_path);
2578 } 2580 }
2579 2581
2580 if(files) { 2582 if(files) {
2581 ucx_map_free(files); 2583 cxMapDestroy(files);
2582 } 2584 }
2583 2585
2584 int ret = 0; 2586 int ret = 0;
2585 2587
2586 // create DavSession 2588 // create DavSession
2587 Repository *repo = get_repository(sstr(dir->repository)); 2589 Repository *repo = get_repository(cx_str(dir->repository));
2588 if(!repo) { 2590 if(!repo) {
2589 fprintf(stderr, "Unkown repository %s\n", dir->name); 2591 fprintf(stderr, "Unkown repository %s\n", dir->name);
2590 return -1; 2592 return -1;
2591 } 2593 }
2592 DavSession *sn = create_session(a, ctx, repo, dir->collection); 2594 DavSession *sn = create_session(a, ctx, repo, dir->collection);
2593 ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db); 2595 util_regdestr(sn->mp, db, (cx_destructor_func)destroy_db);
2594 if (cmd_getoption(a, "verbose")) { 2596 if (cmd_getoption(a, "verbose")) {
2595 curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L); 2597 curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L);
2596 curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr); 2598 curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr);
2597 } 2599 }
2598 2600
2617 } 2619 }
2618 2620
2619 int sync_success = 0; 2621 int sync_success = 0;
2620 int sync_error = 0; 2622 int sync_error = 0;
2621 2623
2622 UcxList *resources = ucx_list_concat(modified, deleted); 2624 // TODO: old code sorted both modified and deleted, is this necessary?
2623 resources = ucx_list_sort(resources, (cmp_func)localres_cmp_path, NULL); 2625 //UcxList *resources = ucx_list_concat(modified, deleted);
2624 2626 //resources = ucx_list_sort(resources, (cmp_func)localres_cmp_path, NULL);
2625 UCX_FOREACH(elm, resources) { 2627 cxListSort(deleted);
2626 LocalResource *resource = elm->data; 2628
2627 2629 CxIterator iter = cxListIterator(modified);
2628 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"); 2630 for(int i=0;i<2;i++) {
2629 if(!res) { 2631 cx_foreach(LocalResource *, resource, iter) {
2630 printf("skip: %s\n", resource->path); 2632 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");
2631 continue; 2633 if(!res) {
2632 } 2634 printf("skip: %s\n", resource->path);
2633 char *status = dav_get_string_property(res, "idav:status"); 2635 continue;
2634 if(status && !strcmp(status, "broken")) { 2636 }
2635 fprintf(stderr, "Resource %s broken\n", res->path); 2637 char *status = dav_get_string_property(res, "idav:status");
2636 continue; 2638 if(status && !strcmp(status, "broken")) {
2637 } 2639 fprintf(stderr, "Resource %s broken\n", res->path);
2638 2640 continue;
2639 DavResource *vres = NULL; 2641 }
2640 DavBool update_local_entry = TRUE; 2642
2641 if(version) { 2643 DavResource *vres = NULL;
2642 if(dir->versioning->type == VERSIONING_SIMPLE) { 2644 DavBool update_local_entry = TRUE;
2643 vres = versioning_simple_find(res, version); 2645 if(version) {
2644 } else if(dir->versioning->type == VERSIONING_DELTAV) { 2646 if(dir->versioning->type == VERSIONING_SIMPLE) {
2645 vres = versioning_deltav_find(res, version); 2647 vres = versioning_simple_find(res, version);
2646 } 2648 } else if(dir->versioning->type == VERSIONING_DELTAV) {
2647 if(!vres) { 2649 vres = versioning_deltav_find(res, version);
2648 fprintf(stderr, "Cannot find specified version for resource %s\n", res->path); 2650 }
2649 ret = 1; 2651 if(!vres) {
2650 break; 2652 fprintf(stderr, "Cannot find specified version for resource %s\n", res->path);
2651 } 2653 ret = 1;
2652 2654 break;
2653 // By restoring an old version of a file, the local dir is not 2655 }
2654 // in sync with the server anymore. Mark this file to change 2656
2655 // the metadata later, to make sure, the file will be detected 2657 // By restoring an old version of a file, the local dir is not
2656 // as locally modified, on the next push/pull 2658 // in sync with the server anymore. Mark this file to change
2657 update_local_entry = FALSE; 2659 // the metadata later, to make sure, the file will be detected
2658 } else { 2660 // as locally modified, on the next push/pull
2659 vres = res; 2661 update_local_entry = FALSE;
2660 }
2661
2662 // download the resource
2663 if(!sync_shutdown) {
2664 if(resource->isdirectory) {
2665 char *local_path = create_local_path(dir, res->path);
2666 if(sys_mkdir(local_path) && errno != EEXIST) {
2667 fprintf(stderr,
2668 "Cannot create directory %s: %s",
2669 local_path, strerror(errno));
2670 }
2671 free(local_path);
2672 } else { 2662 } else {
2673 if(sync_get_resource(a, dir, res->path, vres, db, update_local_entry, &sync_success)) { 2663 vres = res;
2674 fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path); 2664 }
2675 sync_error++; 2665
2676 } else if(!update_local_entry) { 2666 // download the resource
2677 LocalResource *lr = ucx_map_cstr_get(db->resources, res->path); 2667 if(!sync_shutdown) {
2678 if(lr) { 2668 if(resource->isdirectory) {
2679 lr->last_modified = 0; 2669 char *local_path = create_local_path(dir, res->path);
2680 nullfree(lr->hash); 2670 if(sys_mkdir(local_path) && errno != EEXIST) {
2681 lr->hash = NULL; 2671 fprintf(stderr,
2682 } // else should not happen 2672 "Cannot create directory %s: %s",
2683 } 2673 local_path, strerror(errno));
2684 } 2674 }
2685 } 2675 free(local_path);
2676 } else {
2677 if(sync_get_resource(a, dir, res->path, vres, db, update_local_entry, &sync_success)) {
2678 fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path);
2679 sync_error++;
2680 } else if(!update_local_entry) {
2681 LocalResource *lr = cxMapGet(db->resources, cx_hash_key_str(res->path));
2682 if(lr) {
2683 lr->last_modified = 0;
2684 nullfree(lr->hash);
2685 lr->hash = NULL;
2686 } // else should not happen
2687 }
2688 }
2689 }
2690 }
2691 iter = cxListIterator(deleted);
2686 } 2692 }
2687 2693
2688 // unlock repository 2694 // unlock repository
2689 if(locked) { 2695 if(locked) {
2690 if(dav_unlock(root)) { 2696 if(dav_unlock(root)) {
2728 free(size); 2734 free(size);
2729 } 2735 }
2730 2736
2731 void print_outgoing( 2737 void print_outgoing(
2732 CmdArgs *args, 2738 CmdArgs *args,
2733 UcxList *ls_new, 2739 CxList *ls_new,
2734 UcxList *ls_modified, 2740 CxList *ls_modified,
2735 UcxList *ls_conflict, 2741 CxList *ls_conflict,
2736 UcxList *ls_update, 2742 CxList *ls_update,
2737 UcxList *ls_delete, 2743 CxList *ls_delete,
2738 UcxList *ls_move, 2744 CxList *ls_move,
2739 UcxList *ls_copy, 2745 CxList *ls_copy,
2740 UcxList *ls_mkcol) 2746 CxList *ls_mkcol)
2741 { 2747 {
2742 int64_t total_size = 0; 2748 int64_t total_size = 0;
2743 2749
2744 size_t len_new = ucx_list_size(ls_new); 2750 size_t len_new = ls_new->size;
2745 size_t len_mod = ucx_list_size(ls_modified); 2751 size_t len_mod = ls_modified->size;
2746 size_t len_cnf = ucx_list_size(ls_conflict); 2752 size_t len_cnf = ls_conflict->size;
2747 size_t len_upd = ucx_list_size(ls_update); 2753 size_t len_upd = ls_update->size;
2748 size_t len_del = ucx_list_size(ls_delete); 2754 size_t len_del = ls_delete->size;
2749 size_t len_mov = ucx_list_size(ls_move); 2755 size_t len_mov = ls_move->size;
2750 size_t len_cpy = ucx_list_size(ls_copy); 2756 size_t len_cpy = ls_copy->size;
2751 size_t len_mkc = ucx_list_size(ls_mkcol); 2757 size_t len_mkc = ls_mkcol->size;
2752 2758
2753 size_t total = len_new + len_mod + len_cnf + len_upd + len_del + len_mov + len_cpy + len_mkc; 2759 size_t total = len_new + len_mod + len_cnf + len_upd + len_del + len_mov + len_cpy + len_mkc;
2754 if(total == 0) { 2760 if(total == 0) {
2755 printf("no changes\n"); 2761 printf("no changes\n");
2756 return; 2762 return;
2759 printf("%s\n", "File Last Modified Size"); 2765 printf("%s\n", "File Last Modified Size");
2760 printf("%s\n", "=============================================================================="); 2766 printf("%s\n", "==============================================================================");
2761 2767
2762 if(ls_mkcol) { 2768 if(ls_mkcol) {
2763 printf("Directories:\n"); 2769 printf("Directories:\n");
2764 UCX_FOREACH(elm, ls_mkcol) { 2770 CxIterator i = cxListIterator(ls_mkcol);
2765 LocalResource *res = elm->data; 2771 cx_foreach(LocalResource *, res, i) {
2766 printf(" %-49s\n", res->path+1); 2772 printf(" %-49s\n", res->path+1);
2767 total_size += res->size; 2773 total_size += res->size;
2768 } 2774 }
2769 } 2775 }
2770 if(ls_new) { 2776 if(ls_new) {
2771 printf("New:\n"); 2777 printf("New:\n");
2772 UCX_FOREACH(elm, ls_new) { 2778 CxIterator i = cxListIterator(ls_new);
2773 LocalResource *res = elm->data; 2779 cx_foreach(LocalResource *, res, i) {
2774 print_outgoging_file(elm->data); 2780 print_outgoging_file(res);
2775 total_size += res->size; 2781 total_size += res->size;
2776 } 2782 }
2777 } 2783 }
2778 if(ls_modified) { 2784 if(ls_modified) {
2779 printf("Modified:\n"); 2785 printf("Modified:\n");
2780 UCX_FOREACH(elm, ls_modified) { 2786 CxIterator i = cxListIterator(ls_modified);
2781 LocalResource *res = elm->data; 2787 cx_foreach(LocalResource *, res, i) {
2782 print_outgoging_file(elm->data); 2788 print_outgoging_file(res);
2783 total_size += res->size; 2789 total_size += res->size;
2784 } 2790 }
2785 } 2791 }
2786 if(ls_update) { 2792 if(ls_update) {
2787 printf("Update:\n"); 2793 printf("Update:\n");
2788 UCX_FOREACH(elm, ls_update) { 2794 CxIterator i = cxListIterator(ls_update);
2789 LocalResource *res = elm->data; 2795 cx_foreach(LocalResource *, res, i) {
2790 char *lastmodified = util_date_str(res->last_modified); 2796 char *lastmodified = util_date_str(res->last_modified);
2791 printf(" %-49s %12s\n", res->path+1, lastmodified); 2797 printf(" %-49s %12s\n", res->path+1, lastmodified);
2792 free(lastmodified); 2798 free(lastmodified);
2793 } 2799 }
2794 } 2800 }
2795 if(ls_delete) { 2801 if(ls_delete) {
2796 printf("Delete:\n"); 2802 printf("Delete:\n");
2797 UCX_FOREACH(elm, ls_delete) { 2803 CxIterator i = cxListIterator(ls_delete);
2798 LocalResource *res = elm->data; 2804 cx_foreach(LocalResource *, res, i) {
2799 printf(" %s\n", res->path+1); 2805 printf(" %s\n", res->path+1);
2800 } 2806 }
2801 } 2807 }
2802 if(ls_copy) { 2808 if(ls_copy) {
2803 printf("Copy:\n"); 2809 printf("Copy:\n");
2804 UCX_FOREACH(elm, ls_copy) { 2810 CxIterator i = cxListIterator(ls_copy);
2805 LocalResource *res = elm->data; 2811 cx_foreach(LocalResource *, res, i) {
2806 printf("%s -> %s\n", res->origin->path+1, res->path); 2812 printf("%s -> %s\n", res->origin->path+1, res->path);
2807 } 2813 }
2808 } 2814 }
2809 if(ls_move) { 2815 if(ls_move) {
2810 printf("Move:\n"); 2816 printf("Move:\n");
2811 UCX_FOREACH(elm, ls_move) { 2817 CxIterator i = cxListIterator(ls_move);
2812 LocalResource *res = elm->data; 2818 cx_foreach(LocalResource *, res, i) {
2813 printf("%s -> %s\n", res->origin->path+1, res->path); 2819 printf("%s -> %s\n", res->origin->path+1, res->path);
2814 } 2820 }
2815 } 2821 }
2816 if(ls_conflict) { 2822 if(ls_conflict) {
2817 printf("Conflict\n"); 2823 printf("Conflict\n");
2818 UCX_FOREACH(elm, ls_conflict) { 2824 CxIterator i = cxListIterator(ls_conflict);
2819 LocalResource *res = elm->data; 2825 cx_foreach(LocalResource *, res, i) {
2820 printf(" %s\n", res->path+1); 2826 printf(" %s\n", res->path+1);
2821 } 2827 }
2822 } 2828 }
2823 2829
2824 char *total_size_str = util_size_str(FALSE, total_size); 2830 char *total_size_str = util_size_str(FALSE, total_size);
2834 printf("total size: %s\n", total_size_str); 2840 printf("total size: %s\n", total_size_str);
2835 2841
2836 free(total_size_str); 2842 free(total_size_str);
2837 } 2843 }
2838 2844
2839 UcxList* local_scan(SyncDirectory *dir, SyncDatabase *db) { 2845 CxList* local_scan(SyncDirectory *dir, SyncDatabase *db) {
2840 UcxList *resources = NULL; 2846 CxList *resources = cxLinkedListCreateSimple(CX_STORE_POINTERS);
2841 2847
2842 char *path = strdup("/"); 2848 char *path = strdup("/");
2843 UcxList *stack = ucx_list_prepend(NULL, path); 2849 CxList *stack = cxLinkedListCreateSimple(CX_STORE_POINTERS);
2844 while(stack) { 2850 cxListInsert(stack, 0, path);
2851 while(stack->size > 0) {
2845 // get a directory path from the stack and read all entries 2852 // get a directory path from the stack and read all entries
2846 // if an entry is a directory, put it on the stack 2853 // if an entry is a directory, put it on the stack
2847 2854
2848 char *p = stack->data; 2855 char *p = cxListAt(stack, 0);
2849 stack = ucx_list_remove(stack, stack); 2856 cxListRemove(stack, 0);
2850 char *local_path = create_local_path(dir, p); 2857 char *local_path = create_local_path(dir, p);
2851 SYS_DIR local_dir = sys_opendir(local_path); 2858 SYS_DIR local_dir = sys_opendir(local_path);
2852 2859
2853 if(!local_dir) { 2860 if(!local_dir) {
2854 fprintf(stderr, "Cannot open directory %s\n", local_path); 2861 fprintf(stderr, "Cannot open directory %s\n", local_path);
2862 char *new_path = util_concat_path(p, ent->name); 2869 char *new_path = util_concat_path(p, ent->name);
2863 DavBool free_new_path = TRUE; 2870 DavBool free_new_path = TRUE;
2864 LocalResource *res = local_resource_new(dir, db, new_path); 2871 LocalResource *res = local_resource_new(dir, db, new_path);
2865 if(res) { 2872 if(res) {
2866 if(res->isdirectory) { 2873 if(res->isdirectory) {
2867 resources = ucx_list_append(resources, res); 2874 cxListAdd(resources, res);
2868 stack = ucx_list_prepend(stack, new_path); 2875 cxListInsert(stack, 0, new_path);
2869 free_new_path = FALSE; 2876 free_new_path = FALSE;
2870 } else { 2877 } else {
2871 resources = ucx_list_append(resources, res); 2878 cxListAdd(resources, res);
2872 } 2879 }
2873 } 2880 }
2874 if(free_new_path) { 2881 if(free_new_path) {
2875 free(new_path); 2882 free(new_path);
2876 } 2883 }
2883 } 2890 }
2884 2891
2885 return resources; 2892 return resources;
2886 } 2893 }
2887 2894
2888 UcxList* read_changes(SyncDirectory *dir, SyncDatabase *db) {
2889 UcxProperties *parser = ucx_properties_new();
2890 parser->delimiter = ':';
2891
2892 UcxList *resources = NULL;
2893 sstr_t name;
2894 sstr_t value;
2895
2896 char buf[STDIN_BUF_SIZE];
2897 size_t r;
2898 while(!feof(stdin)) {
2899 r = fread(buf, 1, STDIN_BUF_SIZE, stdin);
2900 ucx_properties_fill(parser, buf, r);
2901 while(ucx_properties_next(parser, &name, &value)) {
2902 if(value.length == 0) {
2903 fprintf(stderr, "Wrong input\n");
2904 continue;
2905 }
2906 if(value.ptr[0] == '"'
2907 && value.length > 2
2908 && value.ptr[value.length - 1] == '"')
2909 {
2910 value.ptr[value.length - 1] = '\0';
2911 value.ptr++;
2912 value.length -= 2;
2913 }
2914 value = sstrdup(value);
2915
2916 if(!sstrcmp(name, S("put"))) {
2917 LocalResource *res = local_resource_new(dir, db, value.ptr);
2918 if(res) {
2919 resources = ucx_list_append(resources, res);
2920 }
2921 } else if(!sstrcmp(name, S("remove"))) {
2922 ucx_map_sstr_remove(db->resources, value);
2923 }
2924
2925 free(value.ptr);
2926 }
2927 }
2928 ucx_properties_free(parser);
2929
2930 return resources;
2931 }
2932 2895
2933 LocalResource* local_resource_new(SyncDirectory *dir, SyncDatabase *db, char *path) { 2896 LocalResource* local_resource_new(SyncDirectory *dir, SyncDatabase *db, char *path) {
2934 char *file_path = create_local_path(dir, path); 2897 char *file_path = create_local_path(dir, path);
2935 SYS_STAT s; 2898 SYS_STAT s;
2936 if(sys_lstat(file_path, &s)) { 2899 if(sys_lstat(file_path, &s)) {
3049 3012
3050 int local_resource_is_changed( 3013 int local_resource_is_changed(
3051 SyncDirectory *dir, 3014 SyncDirectory *dir,
3052 SyncDatabase *db, 3015 SyncDatabase *db,
3053 LocalResource *res, 3016 LocalResource *res,
3054 UcxMap *svrres, 3017 CxMap *svrres,
3055 DavBool restore_removed, 3018 DavBool restore_removed,
3056 DavBool restore_modified) 3019 DavBool restore_modified)
3057 { 3020 {
3058 LocalResource *db_res = ucx_map_cstr_get(db->resources, res->path); 3021 LocalResource *db_res = cxMapGet(db->resources, cx_hash_key_str(res->path));
3059 res->tags_updated = 0; 3022 res->tags_updated = 0;
3060 if(db_res) { 3023 if(db_res) {
3061 // copy some metadata from db_res, that localscan does not deliver 3024 // copy some metadata from db_res, that localscan does not deliver
3062 res->tags_updated = db_res->tags_updated; 3025 res->tags_updated = db_res->tags_updated;
3063 if(db_res->etag) { 3026 if(db_res->etag) {
3086 local_resource_copy_parts(db_res, res); 3049 local_resource_copy_parts(db_res, res);
3087 } 3050 }
3088 3051
3089 // check if the file must be restored on the server 3052 // check if the file must be restored on the server
3090 if(svrres) { 3053 if(svrres) {
3091 DavResource *remote = ucx_map_cstr_get(svrres, res->path); 3054 DavResource *remote = cxMapGet(svrres, cx_hash_key_str(res->path));
3092 if(restore_removed && !remote) { 3055 if(restore_removed && !remote) {
3093 return 1; 3056 return 1;
3094 } 3057 }
3095 if(!res->isdirectory && restore_modified && remote) { 3058 if(!res->isdirectory && restore_modified && remote) {
3096 char *etag = dav_get_string_property(remote, "D:getetag"); 3059 char *etag = dav_get_string_property(remote, "D:getetag");
3108 // check if tags have changed 3071 // check if tags have changed
3109 if(db_res->tags_updated) { 3072 if(db_res->tags_updated) {
3110 res->tags_updated = 1; 3073 res->tags_updated = 1;
3111 res->metadata_updated = 1; 3074 res->metadata_updated = 1;
3112 } else if(dir->tagconfig && dir->tagconfig->detect_changes ) { 3075 } else if(dir->tagconfig && dir->tagconfig->detect_changes ) {
3113 UcxBuffer *tags = sync_get_file_tag_data(dir, res); 3076 CxBuffer *tags = sync_get_file_tag_data(dir, res);
3114 if(tags) { 3077 if(tags) {
3115 if(db_res->tags_hash) { 3078 if(db_res->tags_hash) {
3116 char *hash = dav_create_hash(tags->space, tags->size); 3079 char *hash = dav_create_hash(tags->space, tags->size);
3117 if(strcmp(hash, db_res->tags_hash)) { 3080 if(strcmp(hash, db_res->tags_hash)) {
3118 res->tags_updated = 1; 3081 res->tags_updated = 1;
3266 } 3229 }
3267 } else if(!res->etag) { 3230 } else if(!res->etag) {
3268 // the resource is on the server and the client has no etag 3231 // the resource is on the server and the client has no etag
3269 ret = 1; 3232 ret = 1;
3270 } else if(etag) { 3233 } else if(etag) {
3271 sstr_t e = sstr(etag); 3234 cxstring e = cx_str(etag);
3272 if(sstrprefix(e, S("W/"))) { 3235 if(cx_strprefix(e, CX_STR("W/"))) {
3273 e = sstrsubs(e, 2); 3236 e = cx_strsubs(e, 2);
3274 } 3237 }
3275 if(strcmp(e.ptr, res->etag)) { 3238 if(strcmp(e.ptr, res->etag)) {
3276 ret = 1; 3239 ret = 1;
3277 } 3240 }
3278 } else { 3241 } else {
3304 if(!etag) { 3267 if(!etag) {
3305 local->etag = NULL; 3268 local->etag = NULL;
3306 return; 3269 return;
3307 } 3270 }
3308 3271
3309 scstr_t e = scstr(etag); 3272 cxstring e = cx_str(etag);
3310 if(sstrprefix(e, S("W/"))) { 3273 if(cx_strprefix(e, CX_STR("W/"))) {
3311 e = scstrsubs(e, 2); 3274 e = cx_strsubs(e, 2);
3312 } 3275 }
3313 local->etag = sstrdup(e).ptr; 3276 local->etag = cx_strdup(e).ptr;
3314 } 3277 }
3315 3278
3316 char* resource_local_path(DavResource *res) { 3279 char* resource_local_path(DavResource *res) {
3317 #ifdef SYS_LINK_EXT 3280 #ifdef SYS_LINK_EXT
3318 // on Windows, add .lnk extension to links 3281 // on Windows, add .lnk extension to links
3332 if(local->blocksize < 0) { 3295 if(local->blocksize < 0) {
3333 // file splitting disabled 3296 // file splitting disabled
3334 return 0; 3297 return 0;
3335 } else if(local->blocksize > 0) { 3298 } else if(local->blocksize > 0) {
3336 local_blocksize = (size_t)local->blocksize; 3299 local_blocksize = (size_t)local->blocksize;
3337 } else { 3300 } else if(dir->splitconfig) {
3338 UCX_FOREACH(elm, dir->splitconfig) { 3301 CxIterator i = cxListIterator(dir->splitconfig);
3339 SplitConfig *sc = elm->data; 3302 cx_foreach(SplitConfig *, sc, i) {
3340 if(sc->filter) { 3303 if(sc->filter) {
3341 if(res_matches_filter(sc->filter, local->path)) { 3304 if(res_matches_filter(sc->filter, local->path)) {
3342 continue; 3305 continue;
3343 } 3306 }
3344 } 3307 }
3458 DavResource *resource = dav_resource_new(res->session, res->path); 3421 DavResource *resource = dav_resource_new(res->session, res->path);
3459 dav_remove_property(resource, "idav:status"); 3422 dav_remove_property(resource, "idav:status");
3460 int ret = dav_store(resource); 3423 int ret = dav_store(resource);
3461 dav_resource_free(resource); 3424 dav_resource_free(resource);
3462 return ret; 3425 return ret;
3463 }
3464
3465 int sync_tags_equal(UcxList *tags1, UcxList *tags2) {
3466 if(!tags1) {
3467 return tags2 ? 0 : 1;
3468 }
3469 if(!tags2) {
3470 return tags1 ? 0 : 1;
3471 }
3472
3473 UcxMap *map1 = ucx_map_new(32);
3474 UCX_FOREACH(elm, tags1) {
3475 DavTag *t = elm->data;
3476 ucx_map_cstr_put(map1, t->name, t);
3477 }
3478
3479 int equal = 1;
3480 int i = 0;
3481 UCX_FOREACH(elm, tags2) {
3482 DavTag *t = elm->data;
3483 if(!ucx_map_cstr_get(map1, t->name)) {
3484 equal = 0;
3485 break;
3486 }
3487 i++;
3488 }
3489
3490 if(i != map1->count) {
3491 equal = 0;
3492 }
3493 ucx_map_free(map1);
3494 return equal;
3495 } 3426 }
3496 3427
3497 int sync_store_metadata(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res) { 3428 int sync_store_metadata(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res) {
3498 int ret = 0; 3429 int ret = 0;
3499 3430
3543 3474
3544 int sync_store_xattr(SyncDirectory *dir, const char *path, XAttributes *xattr) { 3475 int sync_store_xattr(SyncDirectory *dir, const char *path, XAttributes *xattr) {
3545 // create a map of all currently available local attributes 3476 // create a map of all currently available local attributes
3546 ssize_t nelm = 0; 3477 ssize_t nelm = 0;
3547 char **list = xattr_list(path, &nelm); 3478 char **list = xattr_list(path, &nelm);
3548 UcxMap *current_xattr = NULL; 3479 CxMap *current_xattr = NULL;
3549 if(nelm > 0) { 3480 if(nelm > 0) {
3550 current_xattr = ucx_map_new(nelm + 8); 3481 current_xattr = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, nelm + 8);
3551 for(int i=0;i<nelm;i++) { 3482 for(int i=0;i<nelm;i++) {
3552 // use the xattr name as key and store any value 3483 // use the xattr name as key and store any value
3553 ucx_map_cstr_put(current_xattr, list[i], list[i]); 3484 cxMapPut(current_xattr, cx_hash_key_str(list[i]), list[i]);
3554 } 3485 }
3555 } 3486 }
3556 if(list) { 3487 if(list) {
3557 free(list); 3488 free(list);
3558 } 3489 }
3559 3490
3560 // store extended attributes 3491 // store extended attributes
3561 size_t nattr = xattr ? xattr->nattr : 0; 3492 size_t nattr = xattr ? xattr->nattr : 0;
3562 for(int i=0;i<nattr;i++) { 3493 for(int i=0;i<nattr;i++) {
3563 sstr_t value = xattr->values[i]; 3494 cxmutstr value = xattr->values[i];
3564 if(xattr_set(path, xattr->names[i], value.ptr, value.length)) { 3495 if(xattr_set(path, xattr->names[i], value.ptr, value.length)) {
3565 fprintf(stderr, 3496 fprintf(stderr,
3566 "Cannot store xattr '%s' for file: %s\n", 3497 "Cannot store xattr '%s' for file: %s\n",
3567 xattr->names[i], 3498 xattr->names[i],
3568 path); 3499 path);
3570 3501
3571 if(current_xattr) { 3502 if(current_xattr) {
3572 // to detect which xattributes are removed, we remove all new 3503 // to detect which xattributes are removed, we remove all new
3573 // attributes from the map and all remaining attributes must 3504 // attributes from the map and all remaining attributes must
3574 // be removed with xattr_remove 3505 // be removed with xattr_remove
3575 char *value = ucx_map_cstr_remove(current_xattr, xattr->names[i]); 3506 char *value = cxMapRemoveAndGet(current_xattr, cx_hash_key_str(xattr->names[i]));
3576 if(value) { 3507 if(value) {
3577 free(value); 3508 free(value);
3578 } 3509 }
3579 } 3510 }
3580 } 3511 }
3581 3512
3582 if(current_xattr) { 3513 if(current_xattr) {
3583 UcxMapIterator i = ucx_map_iterator(current_xattr); 3514 CxIterator i = cxMapIteratorValues(current_xattr);
3584 char *value = NULL; 3515 char *value = NULL;
3585 UCX_MAP_FOREACH(key, value, i) { 3516 cx_foreach(char *, value, i) {
3586 (void)xattr_remove(path, value); // don't print error 3517 (void)xattr_remove(path, value); // don't print error
3587 free(value); 3518 free(value);
3588 } 3519 }
3589 ucx_map_free(current_xattr); 3520 cxMapDestroy(current_xattr);
3590 } 3521 }
3591 3522
3592 return 0; 3523 return 0;
3593 } 3524 }
3594 3525
3596 if(!dir->tagconfig) { 3527 if(!dir->tagconfig) {
3597 return 0; 3528 return 0;
3598 } 3529 }
3599 3530
3600 char *remote_hash = NULL; 3531 char *remote_hash = NULL;
3601 UcxList *tags = NULL; 3532 CxList *tags = NULL;
3602 if(dir->tagconfig) { 3533 if(dir->tagconfig) {
3603 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_PROPS_NS, "tags"); 3534 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_PROPS_NS, "tags");
3604 if(tagsprop) { 3535 if(tagsprop) {
3605 tags = parse_dav_xml_taglist(tagsprop); 3536 tags = parse_dav_xml_taglist(tagsprop);
3606 remote_hash = create_tags_hash(tags); 3537 remote_hash = create_tags_hash(tags);
3607 } 3538 }
3608 } 3539 }
3609 3540
3610 DavBool store_tags = FALSE; 3541 DavBool store_tags = FALSE;
3611 DavBool tags_changed = FALSE; 3542 DavBool tags_changed = FALSE;
3612 UcxList *local_tags = sync_get_file_tags(dir, local, &tags_changed, NULL); 3543 CxList *local_tags = sync_get_file_tags(dir, local, &tags_changed, NULL);
3613 if(tags_changed) { 3544 if(tags_changed) {
3614 switch(dir->tagconfig->conflict) { 3545 switch(dir->tagconfig->conflict) {
3615 case TAG_NO_CONFLICT: { 3546 case TAG_NO_CONFLICT: {
3616 store_tags = TRUE; 3547 store_tags = TRUE;
3617 break; 3548 break;
3624 store_tags = TRUE; 3555 store_tags = TRUE;
3625 local->tags_updated = FALSE; 3556 local->tags_updated = FALSE;
3626 break; 3557 break;
3627 } 3558 }
3628 case TAG_MERGE: { 3559 case TAG_MERGE: {
3629 UcxList *new_tags = merge_tags(local_tags, tags); 3560 CxList *new_tags = merge_tags(local_tags, tags);
3630 // TODO: free tags and local_tags 3561 // TODO: free tags and local_tags
3631 tags = new_tags; 3562 tags = new_tags;
3632 store_tags = TRUE; 3563 store_tags = TRUE;
3633 // make sure the merged tags will be pushed the next time 3564 // make sure the merged tags will be pushed the next time
3634 local->tags_updated = TRUE; 3565 local->tags_updated = TRUE;
3635 break; 3566 break;
3636 } 3567 }
3637 } 3568 }
3638 } else { 3569 } else {
3639 if(!sync_tags_equal(tags, local_tags)) { 3570 if(!compare_taglists(tags, local_tags)) {
3640 store_tags = TRUE; 3571 store_tags = TRUE;
3641 } 3572 }
3642 // TODO: free local_tags 3573 // TODO: free local_tags
3643 } 3574 }
3644 3575
3659 // TODO: free stuff 3590 // TODO: free stuff
3660 3591
3661 return ret; 3592 return ret;
3662 } 3593 }
3663 3594
3664 int sync_store_tags_local(SyncDirectory *dir, LocalResource *local, const char *path, UcxList *tags) { 3595 int sync_store_tags_local(SyncDirectory *dir, LocalResource *local, const char *path, CxList *tags) {
3665 int ret = 0; 3596 int ret = 0;
3666 if(dir->tagconfig->store == TAG_STORE_XATTR) { 3597 if(dir->tagconfig->store == TAG_STORE_XATTR) {
3667 UcxBuffer *data = NULL; 3598 CxBuffer *data = NULL;
3668 if(tags) { 3599 if(tags) {
3669 switch(dir->tagconfig->local_format) { 3600 switch(dir->tagconfig->local_format) {
3670 default: break; 3601 default: break;
3671 case TAG_FORMAT_TEXT: { 3602 case TAG_FORMAT_TEXT: {
3672 data = create_text_taglist(tags); 3603 data = create_text_taglist(tags);
3702 local->tags_hash = data_hash; 3633 local->tags_hash = data_hash;
3703 } 3634 }
3704 } else { 3635 } else {
3705 free(data_hash); 3636 free(data_hash);
3706 } 3637 }
3707 ucx_buffer_free(data); 3638 cxBufferFree(data);
3708 } else { 3639 } else {
3709 ret = -1; 3640 ret = -1;
3710 } 3641 }
3711 } else { 3642 } else {
3712 if(local) { 3643 if(local) {
3722 } 3653 }
3723 3654
3724 return ret; 3655 return ret;
3725 } 3656 }
3726 3657
3727 UcxBuffer* sync_get_file_tag_data(SyncDirectory *dir, LocalResource *res) { 3658 CxBuffer* sync_get_file_tag_data(SyncDirectory *dir, LocalResource *res) {
3728 if(!dir->tagconfig) { 3659 if(!dir->tagconfig) {
3729 return NULL; 3660 return NULL;
3730 } 3661 }
3731 if(res->cached_tags) { 3662 if(res->cached_tags) {
3732 return res->cached_tags; 3663 return res->cached_tags;
3733 } 3664 }
3734 UcxBuffer *buf = NULL; 3665 CxBuffer *buf = NULL;
3735 if(dir->tagconfig->store == TAG_STORE_XATTR) { 3666 if(dir->tagconfig->store == TAG_STORE_XATTR) {
3736 ssize_t tag_length = 0; 3667 ssize_t tag_length = 0;
3737 char *local_path = create_local_path(dir, local_resource_path(res)); 3668 char *local_path = create_local_path(dir, local_resource_path(res));
3738 char* tag_data = xattr_get( 3669 char* tag_data = xattr_get(
3739 local_path, 3670 local_path,
3740 dir->tagconfig->xattr_name, 3671 dir->tagconfig->xattr_name,
3741 &tag_length); 3672 &tag_length);
3742 free(local_path); 3673 free(local_path);
3743 3674
3744 if(tag_length > 0) { 3675 if(tag_length > 0) {
3745 buf = ucx_buffer_new(tag_data, (size_t)tag_length, UCX_BUFFER_AUTOFREE); 3676 buf = cxBufferCreate(tag_data, (size_t)tag_length, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS);
3746 buf->size = (size_t)tag_length; 3677 buf->size = (size_t)tag_length;
3747 } 3678 }
3748 } 3679 }
3749 res->cached_tags = buf; 3680 res->cached_tags = buf;
3750 return buf; 3681 return buf;
3751 } 3682 }
3752 3683
3753 UcxList* sync_get_file_tags(SyncDirectory *dir, LocalResource *res, DavBool *changed, char **newhash) { 3684 CxList* sync_get_file_tags(SyncDirectory *dir, LocalResource *res, DavBool *changed, char **newhash) {
3754 if(changed) *changed = FALSE; 3685 if(changed) *changed = FALSE;
3755 3686
3756 UcxList *tags = NULL; 3687 CxList *tags = NULL;
3757 3688
3758 if(!res) { 3689 if(!res) {
3759 return NULL; 3690 return NULL;
3760 } 3691 }
3761 3692
3764 } 3695 }
3765 if(changed && res->tags_updated) { 3696 if(changed && res->tags_updated) {
3766 *changed = TRUE; 3697 *changed = TRUE;
3767 } 3698 }
3768 if(dir->tagconfig->store == TAG_STORE_XATTR) { 3699 if(dir->tagconfig->store == TAG_STORE_XATTR) {
3769 UcxBuffer *tag_buf = res->cached_tags ? 3700 CxBuffer *tag_buf = res->cached_tags ?
3770 res->cached_tags : 3701 res->cached_tags :
3771 sync_get_file_tag_data(dir, res); 3702 sync_get_file_tag_data(dir, res);
3772 3703
3773 if(tag_buf) { 3704 if(tag_buf) {
3774 char *new_hash = dav_create_hash(tag_buf->space, tag_buf->size); 3705 char *new_hash = dav_create_hash(tag_buf->space, tag_buf->size);
4009 } 3940 }
4010 3941
4011 // this macro is only a workaround for a netbeans bug 3942 // this macro is only a workaround for a netbeans bug
4012 #define LOG10 log10 3943 #define LOG10 log10
4013 3944
4014 static UcxList* upload_parts( 3945 static CxList* upload_parts(
4015 LocalResource *local, 3946 LocalResource *local,
4016 DavResource *res, 3947 DavResource *res,
4017 FILE *in, 3948 FILE *in,
4018 uint64_t filesize, 3949 uint64_t filesize,
4019 size_t blocksize, 3950 size_t blocksize,
4065 *err = 1; 3996 *err = 1;
4066 free(buffer); 3997 free(buffer);
4067 return NULL; 3998 return NULL;
4068 } 3999 }
4069 4000
4070 UcxMap *updated_parts_map = ucx_map_new((nblocks/2)+64); 4001 CxMap *updated_parts_map = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, (nblocks/2)+64);
4002 updated_parts_map->simple_destructor = (cx_destructor_func)filepart_free;
4071 4003
4072 int blockindex = 0; 4004 int blockindex = 0;
4073 int uploaded_parts = 0; 4005 int uploaded_parts = 0;
4074 size_t r; 4006 size_t r;
4075 4007
4119 // store the FilePart in a map 4051 // store the FilePart in a map
4120 // later we do a propfind and add the etag 4052 // later we do a propfind and add the etag
4121 FilePart *f = calloc(1, sizeof(FilePart)); 4053 FilePart *f = calloc(1, sizeof(FilePart));
4122 f->block = blockindex; 4054 f->block = blockindex;
4123 f->hash = block_hash; 4055 f->hash = block_hash;
4124 ucx_map_cstr_put(updated_parts_map, name, f); 4056 cxMapPut(updated_parts_map, cx_hash_key_str(name), f);
4125 } 4057 }
4126 dav_resource_free(part); 4058 dav_resource_free(part);
4127 uploaded_parts++; 4059 uploaded_parts++;
4128 } 4060 }
4129 if(*err) { 4061 if(*err) {
4136 // restore flags 4068 // restore flags
4137 res->session->flags = session_flags; 4069 res->session->flags = session_flags;
4138 4070
4139 free(buffer); 4071 free(buffer);
4140 if(*err) { 4072 if(*err) {
4141 ucx_map_free_content(updated_parts_map, (ucx_destructor)filepart_free); 4073 cxMapDestroy(updated_parts_map);
4142 ucx_map_free(updated_parts_map);
4143 return NULL; 4074 return NULL;
4144 } 4075 }
4145 4076
4146 // set content-hash 4077 // set content-hash
4147 unsigned char content_hash[DAV_SHA256_DIGEST_LENGTH]; 4078 unsigned char content_hash[DAV_SHA256_DIGEST_LENGTH];
4149 sync_set_content_hash(res, content_hash); 4080 sync_set_content_hash(res, content_hash);
4150 local->hash = util_hexstr(content_hash, DAV_SHA256_DIGEST_LENGTH); 4081 local->hash = util_hexstr(content_hash, DAV_SHA256_DIGEST_LENGTH);
4151 4082
4152 // get etags from uploaded resources 4083 // get etags from uploaded resources
4153 // also delete everything, that is not part of the file 4084 // also delete everything, that is not part of the file
4154 UcxList *updated_parts = NULL; 4085 CxList *updated_parts = cxLinkedListCreateSimple(CX_STORE_POINTERS);
4155 DavResource *parts = dav_query(res->session, "select D:getetag from %s order by name", res->path); 4086 DavResource *parts = dav_query(res->session, "select D:getetag from %s order by name", res->path);
4156 if(!parts) { 4087 if(!parts) {
4157 print_resource_error(res->session, parts->path); 4088 print_resource_error(res->session, parts->path);
4158 *err = 1; 4089 *err = 1;
4159 ucx_map_free_content(updated_parts_map, (ucx_destructor)filepart_free); 4090 cxMapDestroy(updated_parts_map);
4160 ucx_map_free(updated_parts_map);
4161 return NULL; 4091 return NULL;
4162 } 4092 }
4163 DavResource *part = parts->children; 4093 DavResource *part = parts->children;
4164 while(part) { 4094 while(part) {
4165 FilePart *fp = ucx_map_cstr_remove(updated_parts_map, part->name); 4095 FilePart *fp = cxMapRemoveAndGet(updated_parts_map, cx_hash_key_str(part->name));
4166 // every part we uploaded is in the map 4096 // every part we uploaded is in the map
4167 // if we get parts that are not in the map, someone else uploaded it 4097 // if we get parts that are not in the map, someone else uploaded it
4168 if(fp) { 4098 if(fp) {
4169 char *etag = dav_get_string_property(part, "D:getetag"); 4099 char *etag = dav_get_string_property(part, "D:getetag");
4170 if(etag) { 4100 if(etag) {
4171 if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') { 4101 if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') {
4172 etag = etag + 2; 4102 etag = etag + 2;
4173 } 4103 }
4174 4104
4175 fp->etag = strdup(etag); 4105 fp->etag = strdup(etag);
4176 updated_parts = ucx_list_append(updated_parts, fp); 4106 cxListAdd(updated_parts, fp);
4177 } // else { wtf is wrong with this resource } 4107 } // else { wtf is wrong with this resource }
4178 } else { 4108 } else {
4179 uint64_t name_partnum = 0; 4109 uint64_t name_partnum = 0;
4180 char *res_name = part->name; 4110 char *res_name = part->name;
4181 while(res_name[0] == '0' && res_name[1] != '\0') { 4111 while(res_name[0] == '0' && res_name[1] != '\0') {
4198 } 4128 }
4199 part = part->next; 4129 part = part->next;
4200 } 4130 }
4201 dav_resource_free_all(parts); 4131 dav_resource_free_all(parts);
4202 4132
4203 ucx_map_free_content(updated_parts_map, (ucx_destructor)filepart_free); 4133 cxMapDestroy(updated_parts_map);
4204 ucx_map_free(updated_parts_map);
4205 4134
4206 *err = 0; 4135 *err = 0;
4207 return updated_parts; 4136 return updated_parts;
4208 } 4137 }
4209 4138
4210 void update_parts(LocalResource *local, UcxList *updates, uint64_t numparts) { 4139 void update_parts(LocalResource *local, CxList *updates, uint64_t numparts) {
4211 size_t old_num = local->numparts; 4140 size_t old_num = local->numparts;
4212 if(old_num > numparts) { 4141 if(old_num > numparts) {
4213 // free old parts 4142 // free old parts
4214 for(size_t i=numparts;i<old_num;i++) { 4143 for(size_t i=numparts;i<old_num;i++) {
4215 FilePart p = local->parts[i]; 4144 FilePart p = local->parts[i];
4224 if(numparts != local->numparts) { 4153 if(numparts != local->numparts) {
4225 local->parts = realloc(local->parts, numparts * sizeof(FilePart)); 4154 local->parts = realloc(local->parts, numparts * sizeof(FilePart));
4226 local->numparts = numparts; 4155 local->numparts = numparts;
4227 } 4156 }
4228 4157
4229 UCX_FOREACH(elm, updates) { 4158 if(!updates) {
4230 FilePart *p = elm->data; 4159 return;
4160 }
4161
4162 CxIterator i = cxListIterator(updates);
4163 cx_foreach(FilePart *, p, i) {
4231 if(p->block > numparts) { 4164 if(p->block > numparts) {
4232 // just make sure things don't explode in case some weird stuff 4165 // just make sure things don't explode in case some weird stuff
4233 // is going on 4166 // is going on
4234 continue; 4167 continue;
4235 } 4168 }
4283 return -1; 4216 return -1;
4284 } 4217 }
4285 4218
4286 DavBool issplit = split_blocksize == 0 ? FALSE : TRUE; 4219 DavBool issplit = split_blocksize == 0 ? FALSE : TRUE;
4287 int split_err = 0; 4220 int split_err = 0;
4288 UcxList *parts = NULL; 4221 CxList *parts = NULL;
4289 uint64_t blockcount = 0; 4222 uint64_t blockcount = 0;
4290 4223
4291 if(islink) { 4224 if(islink) {
4292 dav_set_string_property_ns(res, DAV_PROPS_NS, "link", local->link_target); 4225 dav_set_string_property_ns(res, DAV_PROPS_NS, "link", local->link_target);
4293 } else if(issplit) { 4226 } else if(issplit) {
4453 return result; 4386 return result;
4454 } 4387 }
4455 4388
4456 LocalResource *local_origin = local->origin; 4389 LocalResource *local_origin = local->origin;
4457 if(!copy) { 4390 if(!copy) {
4458 ucx_map_cstr_remove(db->resources, local_origin->path); 4391 cxMapRemove(db->resources, cx_hash_key_str(local_origin->path));
4459 } 4392 }
4460 4393
4461 // set resource metadata 4394 // set resource metadata
4462 DavResource *up_res = dav_resource_new(origin->session, local->path); 4395 DavResource *up_res = dav_resource_new(origin->session, local->path);
4463 if(!up_res) { 4396 if(!up_res) {
4494 int sync_delete_remote_resource( 4427 int sync_delete_remote_resource(
4495 SyncDirectory *dir, 4428 SyncDirectory *dir,
4496 DavSession *sn, 4429 DavSession *sn,
4497 LocalResource *local_res, 4430 LocalResource *local_res,
4498 int *counter, 4431 int *counter,
4499 UcxList **cols) 4432 CxList *cols)
4500 { 4433 {
4501 DavResource *res = dav_get(sn, local_res->path, "D:getetag,idav:split"); 4434 DavResource *res = dav_get(sn, local_res->path, "D:getetag,idav:split");
4502 if(!res) { 4435 if(!res) {
4503 return sn->error == DAV_NOT_FOUND ? 0 : 1; 4436 return sn->error == DAV_NOT_FOUND ? 0 : 1;
4504 } 4437 }
4506 int ret = 0; 4439 int ret = 0;
4507 sn->error = DAV_OK; 4440 sn->error = DAV_OK;
4508 if(res->iscollection) { 4441 if(res->iscollection) {
4509 DavXmlNode *split = dav_get_property_ns(res, DAV_NS, "split"); 4442 DavXmlNode *split = dav_get_property_ns(res, DAV_NS, "split");
4510 if(cols) { 4443 if(cols) {
4511 *cols = ucx_list_append(*cols, local_res); 4444 cxListAdd(cols, local_res);
4512 } else if(split || !res->children) { 4445 } else if(split || !res->children) {
4513 printf("delete: %s\n", res->path); 4446 printf("delete: %s\n", res->path);
4514 if(dav_delete(res)) { 4447 if(dav_delete(res)) {
4515 ret = 1; 4448 ret = 1;
4516 fprintf(stderr, "Cannot delete collection %s\n", res->path); 4449 fprintf(stderr, "Cannot delete collection %s\n", res->path);
4580 MetadataHashes hashes = {NULL, NULL, NULL, 0, 0, 0}; 4513 MetadataHashes hashes = {NULL, NULL, NULL, 0, 0, 0};
4581 if(dir->tagconfig) { 4514 if(dir->tagconfig) {
4582 // get local tags 4515 // get local tags
4583 DavBool changed = 0; 4516 DavBool changed = 0;
4584 char *tags_hash = NULL; 4517 char *tags_hash = NULL;
4585 UcxList *tags = sync_get_file_tags(dir, local, &changed, &tags_hash); 4518 CxList *tags = sync_get_file_tags(dir, local, &changed, &tags_hash);
4586 char *new_remote_hash = nullstrdup(tags_hash); 4519 char *new_remote_hash = nullstrdup(tags_hash);
4587 if(changed || local->tags_updated) { 4520 if(changed || local->tags_updated) {
4588 DavBool store_tags = TRUE; 4521 DavBool store_tags = TRUE;
4589 4522
4590 // get remote tags 4523 // get remote tags
4592 p.ns = DAV_PROPS_NS; 4525 p.ns = DAV_PROPS_NS;
4593 p.name = "tags"; 4526 p.name = "tags";
4594 if(dav_load_prop(res, &p, 1) && sn->error != DAV_NOT_FOUND) { 4527 if(dav_load_prop(res, &p, 1) && sn->error != DAV_NOT_FOUND) {
4595 print_resource_error(sn, res->path); 4528 print_resource_error(sn, res->path);
4596 } 4529 }
4597 UcxList *remote_tags = NULL; 4530 CxList *remote_tags = NULL;
4598 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_PROPS_NS, "tags"); 4531 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_PROPS_NS, "tags");
4599 if(tagsprop) { 4532 if(tagsprop) {
4600 remote_tags = parse_dav_xml_taglist(tagsprop); 4533 remote_tags = parse_dav_xml_taglist(tagsprop);
4601 } 4534 }
4602 char *remote_hash = create_tags_hash(remote_tags); 4535 char *remote_hash = create_tags_hash(remote_tags);
4611 store_tags = FALSE; 4544 store_tags = FALSE;
4612 local->tags_updated = FALSE; 4545 local->tags_updated = FALSE;
4613 break; 4546 break;
4614 } 4547 }
4615 case TAG_MERGE: { 4548 case TAG_MERGE: {
4616 UcxList *new_tags = merge_tags(tags, remote_tags); 4549 CxList *new_tags = merge_tags(tags, remote_tags);
4617 free_taglist(tags); 4550 free_taglist(tags);
4618 tags = new_tags; 4551 tags = new_tags;
4619 4552
4620 nullfree(tags_hash); 4553 nullfree(tags_hash);
4621 nullfree(new_remote_hash); 4554 nullfree(new_remote_hash);
4704 4637
4705 return err; 4638 return err;
4706 } 4639 }
4707 4640
4708 void remove_deleted_conflicts(SyncDirectory *dir, SyncDatabase *db) { 4641 void remove_deleted_conflicts(SyncDirectory *dir, SyncDatabase *db) {
4709 char **dc = calloc(sizeof(void*), db->conflict->count); 4642 char **dc = calloc(sizeof(void*), db->conflict->size);
4710 int numdc = 0; 4643 int numdc = 0;
4711 4644
4712 UcxMapIterator i = ucx_map_iterator(db->conflict); 4645 CxIterator i = cxMapIteratorValues(db->conflict);
4713 LocalResource *res; 4646 cx_foreach(LocalResource *, res, i) {
4714 UCX_MAP_FOREACH(key, res, i) {
4715 char *path = create_local_path(dir, res->path); 4647 char *path = create_local_path(dir, res->path);
4716 SYS_STAT s; 4648 SYS_STAT s;
4717 if(sys_stat(path, &s)) { 4649 if(sys_stat(path, &s)) {
4718 if(errno == ENOENT) { 4650 if(errno == ENOENT) {
4719 dc[numdc] = res->path; 4651 dc[numdc] = res->path;
4725 } 4657 }
4726 free(path); 4658 free(path);
4727 } 4659 }
4728 4660
4729 for(int i=0;i<numdc;i++) { 4661 for(int i=0;i<numdc;i++) {
4730 ucx_map_cstr_remove(db->conflict, dc[i]); 4662 cxMapRemove(db->conflict, cx_hash_key_str(dc[i]));
4731 } 4663 }
4732 4664
4733 free(dc); 4665 free(dc);
4734 } 4666 }
4735 4667
4736 static void resolve_skipped(SyncDatabase *db) { 4668 static void resolve_skipped(SyncDatabase *db) {
4737 UcxKey k; 4669 CxIterator i = cxMapIteratorValues(db->resources);
4738 LocalResource *res;
4739 UcxMapIterator i = ucx_map_iterator(db->resources);
4740 int skipped = 0; 4670 int skipped = 0;
4741 UCX_MAP_FOREACH(k, res, i) { 4671 cx_foreach(LocalResource *, res, i) {
4742 if(res->skipped) { 4672 if(res->skipped) {
4743 skipped++; 4673 skipped++;
4744 fprintf(stderr, "skipped from push: %s\n", res->path); 4674 fprintf(stderr, "skipped from push: %s\n", res->path);
4745 } 4675 }
4746 } 4676 }
4775 resolve_skipped(db); 4705 resolve_skipped(db);
4776 4706
4777 int ret = 0; 4707 int ret = 0;
4778 4708
4779 // remove conflicts 4709 // remove conflicts
4780 int num_conflict = db->conflict->count; 4710 int num_conflict = db->conflict->size;
4781 ucx_map_free_content(db->conflict, (ucx_destructor)local_resource_free); 4711 //ucx_map_free_content(db->conflict, (ucx_destructor)local_resource_free);
4782 ucx_map_clear(db->conflict); 4712 cxMapClear(db->conflict);
4783 4713
4784 // store db 4714 // store db
4785 if(store_db(db, dir->database, dir->db_settings)) { 4715 if(store_db(db, dir->database, dir->db_settings)) {
4786 fprintf(stderr, "Cannot store sync db\n"); 4716 fprintf(stderr, "Cannot store sync db\n");
4787 fprintf(stderr, "Abort\n"); 4717 fprintf(stderr, "Abort\n");
4827 int num_err = 0; 4757 int num_err = 0;
4828 4758
4829 int ret = 0; 4759 int ret = 0;
4830 4760
4831 // delete all conflict files 4761 // delete all conflict files
4832 UcxMapIterator i = ucx_map_iterator(db->conflict); 4762 CxIterator i = cxMapIterator(db->conflict);
4833 LocalResource *res; 4763 cx_foreach(LocalResource*, res, i) {
4834 UCX_MAP_FOREACH(key, res, i) {
4835 printf("delete: %s\n", res->path); 4764 printf("delete: %s\n", res->path);
4836 char *path = create_local_path(dir, res->path); 4765 char *path = create_local_path(dir, res->path);
4837 if(sys_unlink(path)) { 4766 if(sys_unlink(path)) {
4838 if(errno != ENOENT) { 4767 if(errno != ENOENT) {
4839 perror("unlink"); 4768 perror("unlink");
4842 } else { 4771 } else {
4843 num_del++; 4772 num_del++;
4844 } 4773 }
4845 free(path); 4774 free(path);
4846 } 4775 }
4847 ucx_map_free_content(db->conflict, (ucx_destructor)local_resource_free); 4776 //ucx_map_free_content(db->conflict, (ucx_destructor)local_resource_free);
4848 ucx_map_clear(db->conflict); 4777 cxMapClear(db->conflict);
4849 4778
4850 // store db 4779 // store db
4851 if(store_db(db, dir->database, dir->db_settings)) { 4780 if(store_db(db, dir->database, dir->db_settings)) {
4852 fprintf(stderr, "Cannot store sync db\n"); 4781 fprintf(stderr, "Cannot store sync db\n");
4853 fprintf(stderr, "Abort\n"); 4782 fprintf(stderr, "Abort\n");
4891 } 4820 }
4892 4821
4893 remove_deleted_conflicts(dir, db); 4822 remove_deleted_conflicts(dir, db);
4894 4823
4895 // get all conflict sources 4824 // get all conflict sources
4896 UcxMapIterator i = ucx_map_iterator(db->conflict); 4825 CxIterator i = cxMapIteratorValues(db->conflict);
4897 LocalResource *res; 4826 CxList* conflict_sources = cxLinkedListCreateSimple(CX_STORE_POINTERS);
4898 UcxList* conflict_sources = NULL; 4827 cx_foreach(LocalResource *, res, i) {
4899 UCX_MAP_FOREACH(key, res, i) { 4828 cxListAdd(conflict_sources, res->conflict_source);
4900 conflict_sources = ucx_list_append(conflict_sources, res->conflict_source);
4901 } 4829 }
4902 4830
4903 // print unique conflict sources 4831 // print unique conflict sources
4904 conflict_sources = ucx_list_sort(conflict_sources, ucx_cmp_str, NULL); 4832 // TODO: set cmpfunc at map creation
4905 UCX_FOREACH(elem, conflict_sources) { 4833 conflict_sources->cmpfunc = (cx_compare_func)strcmp;
4906 char* path = elem->data; 4834 cxListSort(conflict_sources);
4907 if(cmd_getoption(a, "verbose")) { 4835 i = cxListIterator(conflict_sources);
4908 int confl_count = 1; 4836 char *prev = "";
4909 while(elem->next && !strcmp(elem->next->data, path)) { 4837 cx_foreach(char *, path, i) {
4910 elem = elem->next; 4838 // TODO: implement verbose print if(cmd_getoption(a, "verbose"))
4911 ++confl_count; 4839 // printf("%s (%d)\n", path, confl_count);
4912 } 4840 if(!strcmp(path, prev)) {
4913 printf("%s (%d)\n", path, confl_count); 4841 continue;
4914 } else { 4842 }
4915 printf("%s\n", path); 4843
4916 while(elem->next && !strcmp(elem->next->data, path)) { 4844 printf("%s\n", path);
4917 elem = elem->next; 4845
4918 } 4846 prev = path;
4919 }
4920 } 4847 }
4921 4848
4922 // cleanup 4849 // cleanup
4923 destroy_db(db); 4850 destroy_db(db);
4924 4851
5027 4954
5028 if(!dir->versioning) { 4955 if(!dir->versioning) {
5029 fprintf(stderr, "No versioning configured for syncdir %s\n", dir->name); 4956 fprintf(stderr, "No versioning configured for syncdir %s\n", dir->name);
5030 } 4957 }
5031 4958
5032 Repository *repo = get_repository(sstr(dir->repository)); 4959 Repository *repo = get_repository(cx_str(dir->repository));
5033 if(!repo) { 4960 if(!repo) {
5034 fprintf(stderr, "Unknown repository %s\n", dir->repository); 4961 fprintf(stderr, "Unknown repository %s\n", dir->repository);
5035 return -1; 4962 return -1;
5036 } 4963 }
5037 4964
5041 return -1; 4968 return -1;
5042 } 4969 }
5043 remove_deleted_conflicts(dir, db); 4970 remove_deleted_conflicts(dir, db);
5044 4971
5045 DavSession *sn = create_session(a, ctx, repo, dir->collection); 4972 DavSession *sn = create_session(a, ctx, repo, dir->collection);
5046 ucx_mempool_reg_destr(sn->mp, db, (ucx_destructor)destroy_db); 4973 util_regdestr(sn->mp, db, (cx_destructor_func)destroy_db);
5047 if (cmd_getoption(a, "verbose")) { 4974 if (cmd_getoption(a, "verbose")) {
5048 curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L); 4975 curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L);
5049 curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr); 4976 curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr);
5050 } 4977 }
5051 4978
5077 ret = 1; 5004 ret = 1;
5078 break; 5005 break;
5079 } 5006 }
5080 5007
5081 DavResource *child = vcol->children; 5008 DavResource *child = vcol->children;
5082 UcxList *children = NULL; 5009 CxList *children = cxLinkedListCreate(cxDefaultAllocator, (cx_compare_func)strcmp, CX_STORE_POINTERS);
5083 while(child) { 5010 while(child) {
5084 children = ucx_list_append(children, child); 5011 cxListAdd(children, child);
5085 child = child->next; 5012 child = child->next;
5086 } 5013 }
5087 children = ucx_list_sort(children, ucx_cmp_str, NULL); 5014 cxListSort(children);
5088 5015
5089 DavBool first = 1; 5016 DavBool first = 1;
5090 UCX_FOREACH(elm, children) { 5017 CxIterator i = cxListIterator(children);
5091 DavResource *c = elm->data; 5018 cx_foreach(DavResource *, c, i) {
5092 if(!first) { 5019 if(!first) {
5093 putchar('\n'); 5020 putchar('\n');
5094 } 5021 }
5095 print_resource_version(c, c->name); 5022 print_resource_version(c, c->name);
5096 first = 0; 5023 first = 0;
5097 } 5024 }
5098 ucx_list_free(children); 5025 cxListDestroy(children);
5099 } while(0); 5026 } while(0);
5100 } else if(dir->versioning->type == VERSIONING_DELTAV) { 5027 } else if(dir->versioning->type == VERSIONING_DELTAV) {
5101 DavResource *versions = dav_versiontree(res, NULL); 5028 DavResource *versions = dav_versiontree(res, NULL);
5102 DavResource *v = versions; 5029 DavResource *v = versions;
5103 DavBool first = 1; 5030 DavBool first = 1;
5269 } 5196 }
5270 return cmd_tagop(args, CMD_TAG_LIST); 5197 return cmd_tagop(args, CMD_TAG_LIST);
5271 } 5198 }
5272 5199
5273 int cmd_tagop(CmdArgs *args, int cmd) { 5200 int cmd_tagop(CmdArgs *args, int cmd) {
5201 // TODO: port to ucx 3
5202 return 1;
5203 #if 0
5204
5274 SyncFile file; 5205 SyncFile file;
5275 int ret = 0; 5206 int ret = 0;
5276 char *path = args->argv[0]; 5207 char *path = args->argv[0];
5277 5208
5278 int err = sync_get_file(args, path, &file, TRUE); 5209 int err = sync_get_file(args, path, &file, TRUE);
5291 fprintf(stderr, "Cannot load sync directory database\n"); 5222 fprintf(stderr, "Cannot load sync directory database\n");
5292 return -1; 5223 return -1;
5293 } 5224 }
5294 5225
5295 LocalResource *newres = NULL; 5226 LocalResource *newres = NULL;
5296 LocalResource *localres = ucx_map_cstr_get(db->resources, file.path); 5227 LocalResource *localres = cxMapGet(db->resources, cx_hash_key_str(file.path));
5297 if(!localres) { 5228 if(!localres) {
5298 newres = calloc(1, sizeof(LocalResource)); 5229 newres = calloc(1, sizeof(LocalResource));
5299 newres->path = strdup(file.path); 5230 newres->path = strdup(file.path);
5300 localres = newres; 5231 localres = newres;
5301 } 5232 }
5302 UcxList *tags = NULL; 5233 CxList *tags = NULL;
5303 DavBool store_tags = FALSE; 5234 DavBool store_tags = FALSE;
5304 5235
5305 if(cmd != CMD_TAG_SET) { 5236 if(cmd != CMD_TAG_SET) {
5306 char *tag = args->argv[1]; 5237 char *tag = args->argv[1];
5307 char *tagcolor = NULL; // TODO: get color 5238 char *tagcolor = NULL; // TODO: get color
5308 5239
5309 tags = sync_get_file_tags(file.dir, localres, NULL, NULL); 5240 tags = sync_get_file_tags(file.dir, localres, NULL, NULL);
5310 UcxList *x = NULL; 5241 CxList *x = NULL;
5311 UCX_FOREACH(elm, tags) { 5242 UCX_FOREACH(elm, tags) {
5312 DavTag *t = elm->data; 5243 DavTag *t = elm->data;
5313 if(cmd == CMD_TAG_LIST) { 5244 if(cmd == CMD_TAG_LIST) {
5314 printf("%s\n", t->name); 5245 printf("%s\n", t->name);
5315 } else if(!strcmp(t->name, tag)) { 5246 } else if(!strcmp(t->name, tag)) {
5372 ret = -2; 5303 ret = -2;
5373 } 5304 }
5374 5305
5375 free(file.path); 5306 free(file.path);
5376 return ret; 5307 return ret;
5308 #endif
5377 } 5309 }
5378 5310
5379 int isfileindir(SyncDirectory *dir, const char *path, SyncFile *f) { 5311 int isfileindir(SyncDirectory *dir, const char *path, SyncFile *f) {
5380 char *fullpath; 5312 char *fullpath;
5381 if(path[0] != '/') { 5313 if(path[0] != '/') {
5404 } 5336 }
5405 5337
5406 // TODO: normalize path 5338 // TODO: normalize path
5407 DavBool not_in_dir = 0; 5339 DavBool not_in_dir = 0;
5408 5340
5409 scstr_t fp = scstr(fullpath); 5341 cxstring fp = cx_str(fullpath);
5410 scstr_t dp = scstr(dir->path); 5342 cxstring dp = cx_str(dir->path);
5411 if(fp.length == dp.length) { 5343 if(fp.length == dp.length) {
5412 if(sstrcmp(fp, dp)) { 5344 if(cx_strcmp(fp, dp)) {
5413 not_in_dir = 1; 5345 not_in_dir = 1;
5414 } 5346 }
5415 } else if(fp.length < dp.length) { 5347 } else if(fp.length < dp.length) {
5416 not_in_dir = 1; 5348 not_in_dir = 1;
5417 } else { 5349 } else {
5418 if(!sstrprefix(fp, dp)) { 5350 if(!cx_strprefix(fp, dp)) {
5419 not_in_dir = 1; 5351 not_in_dir = 1;
5420 } else { 5352 } else {
5421 if(dp.ptr[dp.length-1] == '/') { 5353 if(dp.ptr[dp.length-1] == '/') {
5422 dp.length--; 5354 dp.length--;
5423 } 5355 }
5464 return 4; 5396 return 4;
5465 } 5397 }
5466 } else { 5398 } else {
5467 SyncDirectory *target = NULL; 5399 SyncDirectory *target = NULL;
5468 5400
5469 UcxMapIterator i = scfg_directory_iterator(); 5401 CxIterator i = scfg_directory_iterator();
5470 UcxKey k; 5402 cx_foreach(SyncDirectory *, dir, i) {
5471 SyncDirectory *dir;
5472 UCX_MAP_FOREACH(key, dir, i) {
5473 if(isfileindir(dir, path, f)) { 5403 if(isfileindir(dir, path, f)) {
5474 if(target) { 5404 if(target) {
5475 return 5; 5405 return 5;
5476 } else { 5406 } else {
5477 target = dir; 5407 target = dir;
5498 } 5428 }
5499 } 5429 }
5500 5430
5501 5431
5502 int cmd_add_directory(CmdArgs *args) { 5432 int cmd_add_directory(CmdArgs *args) {
5433 /*
5503 if(!get_repositories()) { 5434 if(!get_repositories()) {
5504 fprintf(stderr, "No repositories available. Run 'dav add-repository' first.\n"); 5435 fprintf(stderr, "No repositories available. Run 'dav add-repository' first.\n");
5505 fprintf(stderr, "Abort\n"); 5436 fprintf(stderr, "Abort\n");
5506 return -1; 5437 return -1;
5507 } 5438 }
5439 */
5440
5441 // TODO: port to ucx 3
5442 return 1;
5443 #if 0
5508 5444
5509 printf("Each sync directory must have an unique name.\n"); 5445 printf("Each sync directory must have an unique name.\n");
5510 char *name = assistant_getcfg("name"); 5446 char *name = assistant_getcfg("name");
5511 if(!name) { 5447 if(!name) {
5512 fprintf(stderr, "Abort\n"); 5448 fprintf(stderr, "Abort\n");
5523 fprintf(stderr, "Abort\n"); 5459 fprintf(stderr, "Abort\n");
5524 return -1; 5460 return -1;
5525 } 5461 }
5526 5462
5527 printf("Specify webdav repository.\n"); 5463 printf("Specify webdav repository.\n");
5528 UcxList *repos = get_repositories(); 5464 CxIterator repos = get_repositories();
5529 int i = 0; 5465 int i = 0;
5530 UCX_FOREACH(elm, repos) { 5466 cx_foreach(Repository *, r, repos) {
5531 Repository *r = elm->data;
5532 printf("%d) %s\n", i, r->name); 5467 printf("%d) %s\n", i, r->name);
5533 i++; 5468 i++;
5534 } 5469 }
5535 char *repository = assistant_getcfg("repository"); 5470 char *repository = assistant_getcfg("repository");
5536 char *reponame = NULL; 5471 char *reponame = NULL;
5588 free(repository); 5523 free(repository);
5589 free(collection); 5524 free(collection);
5590 free(db); 5525 free(db);
5591 5526
5592 return ret; 5527 return ret;
5528 #endif
5593 } 5529 }
5594 5530
5595 int cmd_list_dirs() { 5531 int cmd_list_dirs() {
5596 UcxMapIterator iter = scfg_directory_iterator(); 5532 CxIterator iter = scfg_directory_iterator();
5597 SyncDirectory *dir; 5533 cx_foreach(SyncDirectory *, dir, iter) {
5598 UCX_MAP_FOREACH(key, dir, iter) {
5599 printf("%s\n", dir->name); 5534 printf("%s\n", dir->name);
5600 } 5535 }
5601 return 0; 5536 return 0;
5602 } 5537 }
5603 5538
5604 int cmd_check_repositories(CmdArgs *a) { 5539 int cmd_check_repositories(CmdArgs *a) {
5605 int ret = EXIT_SUCCESS; 5540 int ret = EXIT_SUCCESS;
5606 5541
5607 UcxList *reponames = NULL; 5542 CxList *reponames = cxLinkedListCreateSimple(CX_STORE_POINTERS);
5608 { 5543 {
5609 UcxMapIterator iter = scfg_directory_iterator(); 5544 CxIterator iter = scfg_directory_iterator();
5610 SyncDirectory *dir; 5545 cx_foreach(SyncDirectory *, dir, iter) {
5611 UCX_MAP_FOREACH(key, dir, iter) { 5546 cxListAdd(reponames, dir->repository);
5612 reponames = ucx_list_append(reponames, dir->repository); 5547 }
5613 } 5548 }
5614 } 5549
5615 5550 CxIterator iter = cxListIterator(reponames);
5616 UCX_FOREACH(listelem, reponames) { 5551 cx_foreach(char *, reponame, iter) {
5617 char *reponame = listelem->data;
5618 printf("Checking %s... ", reponame); 5552 printf("Checking %s... ", reponame);
5619 Repository* repo = get_repository(sstr(reponame)); 5553 Repository* repo = get_repository(cx_str(reponame));
5620 if (!repo) { 5554 if (!repo) {
5621 printf(" not found in config.xml!\n"); 5555 printf(" not found in config.xml!\n");
5622 ret = EXIT_FAILURE; 5556 ret = EXIT_FAILURE;
5623 } else { 5557 } else {
5624 DavSession *sn = create_session(a, ctx, repo, repo->url); 5558 DavSession *sn = create_session(a, ctx, repo, repo->url);
5638 ret = EXIT_FAILURE; 5572 ret = EXIT_FAILURE;
5639 } 5573 }
5640 } 5574 }
5641 } 5575 }
5642 5576
5643 ucx_list_free(reponames); 5577 cxListDestroy(reponames);
5644 5578
5645 return ret; 5579 return ret;
5646 } 5580 }
5647 5581
5648 char* create_locktoken_file(const char *syncdirname, const char *locktoken) { 5582 char* create_locktoken_file(const char *syncdirname, const char *locktoken) {
5649 sstr_t fname = ucx_sprintf("locktoken-%s.txt", syncdirname); 5583 cxmutstr fname = cx_asprintf("locktoken-%s.txt", syncdirname);
5650 char *path = config_file_path(fname.ptr); 5584 char *path = config_file_path(fname.ptr);
5651 free(fname.ptr); 5585 free(fname.ptr);
5652 5586
5653 FILE *file = sys_fopen(path, "w"); 5587 FILE *file = sys_fopen(path, "w");
5654 if(file) { 5588 if(file) {

mercurial