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) { |