31 #include <string.h> |
31 #include <string.h> |
32 #include <errno.h> |
32 #include <errno.h> |
33 #include <unistd.h> |
33 #include <unistd.h> |
34 #include <signal.h> |
34 #include <signal.h> |
35 #include <time.h> |
35 #include <time.h> |
|
36 #include <utime.h> |
36 #include <libxml/xmlerror.h> |
37 #include <libxml/xmlerror.h> |
37 #include <sys/types.h> |
38 #include <sys/types.h> |
38 #include <ucx/string.h> |
39 #include <ucx/string.h> |
39 #include <ucx/utils.h> |
40 #include <ucx/utils.h> |
40 #include <ucx/properties.h> |
41 #include <ucx/properties.h> |
497 locked = TRUE; |
498 locked = TRUE; |
498 locktokenfile = create_locktoken_file(dir->name, lock->token); |
499 locktokenfile = create_locktoken_file(dir->name, lock->token); |
499 } |
500 } |
500 |
501 |
501 int ret = 0; |
502 int ret = 0; |
502 DavResource *ls = dav_query(sn, "select D:getetag,idav:status,idav:tags from / with depth = infinity"); |
503 DavResource *ls = dav_query(sn, "select D:getetag,idav:status,idav:tags,idav:finfo,idav:xattributes from / with depth = infinity"); |
503 if(!ls) { |
504 if(!ls) { |
504 print_resource_error(sn, "/"); |
505 print_resource_error(sn, "/"); |
505 if(locked) { |
506 if(locked) { |
506 if(dav_unlock(root)) { |
507 if(dav_unlock(root)) { |
507 print_resource_error(sn, "/"); |
508 print_resource_error(sn, "/"); |
547 UcxList *res_mkdir = NULL; |
548 UcxList *res_mkdir = NULL; |
548 UcxList *res_metadata = NULL; |
549 UcxList *res_metadata = NULL; |
549 UcxList *res_broken = NULL; |
550 UcxList *res_broken = NULL; |
550 UcxList *lres_removed = NULL; // list of LocalResource* |
551 UcxList *lres_removed = NULL; // list of LocalResource* |
551 |
552 |
552 UcxMap *svrres = ucx_map_new(db->resources->count); |
553 //UcxMap *svrres = ucx_map_new(db->resources->count); |
553 UcxMap *dbres = ucx_map_clone(db->resources, NULL, NULL); |
554 UcxMap *dbres = ucx_map_clone(db->resources, NULL, NULL); |
554 |
555 |
555 UcxList *statls = NULL; |
556 UcxList *statls = NULL; |
556 |
557 |
557 UcxList *stack = ucx_list_prepend(NULL, ls->children); |
558 UcxList *stack = ucx_list_prepend(NULL, ls->children); |
693 break; |
694 break; |
694 } |
695 } |
695 |
696 |
696 LocalResource *local = ucx_map_cstr_get(db->resources, res->path); |
697 LocalResource *local = ucx_map_cstr_get(db->resources, res->path); |
697 if(local) { |
698 if(local) { |
|
699 printf("update: %s\n", res->path); |
698 char *local_path = util_concat_path(dir->path, res->path); |
700 char *local_path = util_concat_path(dir->path, res->path); |
699 if(sync_store_tags(dir, local_path, local, res)) { |
701 if(sync_store_metadata(dir, local_path, local, res)) { |
700 fprintf(stderr, "Tag update failed: %s\n", res->path); |
702 fprintf(stderr, "Metadata update failed: %s\n", res->path); |
|
703 sync_error++; |
|
704 } else { |
|
705 struct stat s; |
|
706 if(stat(local_path, &s)) { |
|
707 fprintf(stderr, "Cannot stat file after update: %s\n", strerror(errno)); |
|
708 } |
|
709 sync_set_metadata_from_stat(local, &s); |
|
710 sync_success++; |
701 } |
711 } |
702 free(local_path); |
712 free(local_path); |
703 } else { |
713 } else { |
704 // this should never happen but who knows |
714 // this should never happen but who knows |
705 fprintf(stderr, |
715 fprintf(stderr, |
817 if(sstrprefix(e, S("W/"))) { |
827 if(sstrprefix(e, S("W/"))) { |
818 e = sstrsubs(e, 2); |
828 e = sstrsubs(e, 2); |
819 } |
829 } |
820 if(!strcmp(e.ptr, local->etag)) { |
830 if(!strcmp(e.ptr, local->etag)) { |
821 // resource is already up-to-date on the client |
831 // resource is already up-to-date on the client |
822 |
|
823 // TODO: detect metadata update |
|
824 //sync_store_tags(dir, local_path, local, res); |
|
825 nochange = TRUE; |
832 nochange = TRUE; |
826 } |
833 } |
827 } |
834 } |
828 |
835 |
829 if(!nochange) { |
836 if(!nochange) { |
836 ret = type; |
843 ret = type; |
837 } else { |
844 } else { |
838 ret = REMOTE_CHANGE_NEW; |
845 ret = REMOTE_CHANGE_NEW; |
839 } |
846 } |
840 |
847 |
841 if(ret == REMOTE_NO_CHANGE) { |
848 while(ret == REMOTE_NO_CHANGE && local) { |
842 // check if tags have changed |
849 // check if tags have changed |
843 if(dir->tagconfig) { |
850 if(dir->tagconfig) { |
|
851 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_NS, "tags"); |
|
852 UcxList *remote_tags = NULL; |
|
853 if(tagsprop) { |
|
854 remote_tags = parse_dav_xml_taglist(tagsprop); |
|
855 } |
|
856 char *remote_hash = create_tags_hash(remote_tags); |
|
857 if(nullstrcmp(remote_hash, local->remote_tags_hash)) { |
|
858 ret = REMOTE_CHANGE_METADATA; |
|
859 } |
|
860 if(remote_hash) { |
|
861 free(remote_hash); |
|
862 } |
|
863 free_taglist(remote_tags); |
844 |
864 |
845 } |
865 if(ret == REMOTE_CHANGE_METADATA) { |
846 |
866 break; |
|
867 } |
|
868 } |
|
869 |
|
870 // check if extended attributes have changed |
|
871 if(dir->metadata & FINFO_XATTR == FINFO_XATTR) { |
|
872 DavXmlNode *xattr = dav_get_property_ns(res, DAV_NS, "xattributes"); |
|
873 char *xattr_hash = get_xattr_hash(xattr); |
|
874 if(nullstrcmp(xattr_hash, local->xattr_hash)) { |
|
875 ret = REMOTE_CHANGE_METADATA; |
|
876 break; |
|
877 } |
|
878 } |
|
879 |
|
880 // check if finfo has changed |
|
881 DavXmlNode *finfo = dav_get_property_ns(res, DAV_NS, "finfo"); |
|
882 if(dir->metadata & FINFO_MODE == FINFO_MODE) { |
|
883 FileInfo f; |
|
884 finfo_get_values(finfo, &f); |
|
885 if(f.mode_set && f.mode != local->mode) { |
|
886 ret = REMOTE_CHANGE_METADATA; |
|
887 break; |
|
888 } |
|
889 } |
|
890 |
|
891 break; |
847 } |
892 } |
848 |
893 |
849 free(local_path); |
894 free(local_path); |
850 return ret; |
895 return ret; |
|
896 } |
|
897 |
|
898 void sync_set_metadata_from_stat(LocalResource *local, struct stat *s) { |
|
899 local->last_modified = s->st_mtime; |
|
900 local->mode = s->st_mode & 07777; |
|
901 local->uid = s->st_uid; |
|
902 local->gid = s->st_gid; |
|
903 local->size = s->st_size; |
851 } |
904 } |
852 |
905 |
853 int sync_get_resource( |
906 int sync_get_resource( |
854 CmdArgs *a, |
907 CmdArgs *a, |
855 SyncDirectory *dir, |
908 SyncDirectory *dir, |
885 } |
938 } |
886 fclose(out); |
939 fclose(out); |
887 |
940 |
888 if(ret == 0) { |
941 if(ret == 0) { |
889 (*counter)++; |
942 (*counter)++; |
|
943 |
|
944 if(sync_store_metadata(dir, tmp_path, local, res)) { |
|
945 fprintf(stderr, "Cannot store metadata: %s\n", res->path); |
|
946 } |
890 |
947 |
891 if(dir->trash && dir->backuppull) { |
948 if(dir->trash && dir->backuppull) { |
892 move_to_trash(dir, local_path); |
949 move_to_trash(dir, local_path); |
893 } |
950 } |
894 if(sys_rename(tmp_path, local_path)) { |
951 if(sys_rename(tmp_path, local_path)) { |
916 } |
973 } |
917 |
974 |
918 if(local->etag) { |
975 if(local->etag) { |
919 free(local->etag); |
976 free(local->etag); |
920 } |
977 } |
|
978 |
921 // set metadata from stat |
979 // set metadata from stat |
922 local->etag = strdup(etag); |
980 local->etag = strdup(etag); |
923 local->last_modified = s.st_mtime; |
981 sync_set_metadata_from_stat(local, &s); |
924 local->size = s.st_size; |
|
925 local->skipped = FALSE; |
982 local->skipped = FALSE; |
926 |
|
927 sync_store_tags(dir, tmp_path, local, res); |
|
928 } else { |
983 } else { |
929 if(sys_unlink(tmp_path)) { |
984 if(sys_unlink(tmp_path)) { |
930 fprintf(stderr, "Cannot remove tmp file: %s\n", tmp_path); |
985 fprintf(stderr, "Cannot remove tmp file: %s\n", tmp_path); |
931 } |
986 } |
932 } |
987 } |
1952 } |
2012 } |
1953 ucx_map_free(map1); |
2013 ucx_map_free(map1); |
1954 return equal; |
2014 return equal; |
1955 } |
2015 } |
1956 |
2016 |
|
2017 int sync_store_metadata(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res) { |
|
2018 int ret = 0; |
|
2019 |
|
2020 DavXmlNode *fileinfo = dav_get_property_ns(res, DAV_NS, "finfo"); |
|
2021 if(fileinfo) { |
|
2022 FileInfo f; |
|
2023 finfo_get_values(fileinfo, &f); |
|
2024 if(dir->metadata & FINFO_DATE == FINFO_DATE && f.date_set) { |
|
2025 // set mtime |
|
2026 struct utimbuf t; |
|
2027 t.actime = f.last_modified; |
|
2028 t.modtime = f.last_modified; |
|
2029 if(utime(path, &t)) { |
|
2030 fprintf(stderr, "utime failed for file: %s : %s\n", path, strerror(errno)); |
|
2031 ret = 1; |
|
2032 } |
|
2033 } |
|
2034 if(dir->metadata & FINFO_MODE == FINFO_MODE && f.mode_set) { |
|
2035 // set mode |
|
2036 if(chmod(path, f.mode)) { |
|
2037 fprintf(stderr, "chmod failed for file: %s : %s\n", path, strerror(errno)); |
|
2038 ret = 1; |
|
2039 } |
|
2040 } |
|
2041 } |
|
2042 |
|
2043 DavXmlNode *xattr_prop = dav_get_property_ns(res, DAV_NS, "xattributes"); |
|
2044 if(xattr_prop) { |
|
2045 XAttributes *xattr = xml_get_attributes(xattr_prop); |
|
2046 if(xattr) { |
|
2047 if(!sync_store_xattr(dir, path, xattr)) { |
|
2048 if(local->xattr_hash) { |
|
2049 free(local->xattr_hash); |
|
2050 } |
|
2051 local->xattr_hash = xattr->hash; |
|
2052 } |
|
2053 } |
|
2054 } |
|
2055 |
|
2056 if(sync_store_tags(dir, path, local, res)) { |
|
2057 ret = 1; |
|
2058 } |
|
2059 |
|
2060 return ret; |
|
2061 } |
|
2062 |
|
2063 int sync_store_xattr(SyncDirectory *dir, const char *path, XAttributes *xattr) { |
|
2064 for(int i=0;i<xattr->nattr;i++) { |
|
2065 sstr_t value = xattr->values[i]; |
|
2066 if(xattr_set(path, xattr->names[i], value.ptr, value.length)) { |
|
2067 fprintf( |
|
2068 stderr, |
|
2069 "Cannot store xattr '%s' for file: %s\n", |
|
2070 xattr->names[i], |
|
2071 path); |
|
2072 } |
|
2073 } |
|
2074 return 0; |
|
2075 } |
|
2076 |
1957 int sync_store_tags(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res) { |
2077 int sync_store_tags(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res) { |
1958 if(!dir->tagconfig) { |
2078 if(!dir->tagconfig) { |
1959 return 0; |
2079 return 0; |
1960 } |
2080 } |
1961 |
2081 |
1971 DavBool store_tags = FALSE; |
2091 DavBool store_tags = FALSE; |
1972 DavBool tags_changed = FALSE; |
2092 DavBool tags_changed = FALSE; |
1973 UcxList *local_tags = sync_get_file_tags(dir, local, &tags_changed, NULL); |
2093 UcxList *local_tags = sync_get_file_tags(dir, local, &tags_changed, NULL); |
1974 if(tags_changed) { |
2094 if(tags_changed) { |
1975 switch(dir->tagconfig->conflict) { |
2095 switch(dir->tagconfig->conflict) { |
1976 case TAG_NO_CONFLICT: |
2096 case TAG_NO_CONFLICT: { |
|
2097 store_tags = TRUE; |
|
2098 break; |
|
2099 } |
1977 case TAG_KEEP_LOCAL: { |
2100 case TAG_KEEP_LOCAL: { |
1978 store_tags = FALSE; |
2101 store_tags = FALSE; |
1979 break; |
2102 break; |
1980 } |
2103 } |
1981 case TAG_KEEP_REMOTE: { |
2104 case TAG_KEEP_REMOTE: { |