diff -r 26a1d5b9d9d2 -r e3c0440bd599 dav/sync.c --- a/dav/sync.c Sun Mar 17 15:00:48 2019 +0100 +++ b/dav/sync.c Sun Mar 17 18:11:31 2019 +0100 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -499,7 +500,7 @@ } int ret = 0; - DavResource *ls = dav_query(sn, "select D:getetag,idav:status,idav:tags from / with depth = infinity"); + DavResource *ls = dav_query(sn, "select D:getetag,idav:status,idav:tags,idav:finfo,idav:xattributes from / with depth = infinity"); if(!ls) { print_resource_error(sn, "/"); if(locked) { @@ -549,7 +550,7 @@ UcxList *res_broken = NULL; UcxList *lres_removed = NULL; // list of LocalResource* - UcxMap *svrres = ucx_map_new(db->resources->count); + //UcxMap *svrres = ucx_map_new(db->resources->count); UcxMap *dbres = ucx_map_clone(db->resources, NULL, NULL); UcxList *statls = NULL; @@ -695,9 +696,18 @@ LocalResource *local = ucx_map_cstr_get(db->resources, res->path); if(local) { + printf("update: %s\n", res->path); char *local_path = util_concat_path(dir->path, res->path); - if(sync_store_tags(dir, local_path, local, res)) { - fprintf(stderr, "Tag update failed: %s\n", res->path); + if(sync_store_metadata(dir, local_path, local, res)) { + fprintf(stderr, "Metadata update failed: %s\n", res->path); + sync_error++; + } else { + struct stat s; + if(stat(local_path, &s)) { + fprintf(stderr, "Cannot stat file after update: %s\n", strerror(errno)); + } + sync_set_metadata_from_stat(local, &s); + sync_success++; } free(local_path); } else { @@ -819,9 +829,6 @@ } if(!strcmp(e.ptr, local->etag)) { // resource is already up-to-date on the client - - // TODO: detect metadata update - //sync_store_tags(dir, local_path, local, res); nochange = TRUE; } } @@ -838,18 +845,64 @@ ret = REMOTE_CHANGE_NEW; } - if(ret == REMOTE_NO_CHANGE) { + while(ret == REMOTE_NO_CHANGE && local) { // check if tags have changed if(dir->tagconfig) { + DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_NS, "tags"); + UcxList *remote_tags = NULL; + if(tagsprop) { + remote_tags = parse_dav_xml_taglist(tagsprop); + } + char *remote_hash = create_tags_hash(remote_tags); + if(nullstrcmp(remote_hash, local->remote_tags_hash)) { + ret = REMOTE_CHANGE_METADATA; + } + if(remote_hash) { + free(remote_hash); + } + free_taglist(remote_tags); + if(ret == REMOTE_CHANGE_METADATA) { + break; + } } + // check if extended attributes have changed + if(dir->metadata & FINFO_XATTR == FINFO_XATTR) { + DavXmlNode *xattr = dav_get_property_ns(res, DAV_NS, "xattributes"); + char *xattr_hash = get_xattr_hash(xattr); + if(nullstrcmp(xattr_hash, local->xattr_hash)) { + ret = REMOTE_CHANGE_METADATA; + break; + } + } + + // check if finfo has changed + DavXmlNode *finfo = dav_get_property_ns(res, DAV_NS, "finfo"); + if(dir->metadata & FINFO_MODE == FINFO_MODE) { + FileInfo f; + finfo_get_values(finfo, &f); + if(f.mode_set && f.mode != local->mode) { + ret = REMOTE_CHANGE_METADATA; + break; + } + } + + break; } free(local_path); return ret; } +void sync_set_metadata_from_stat(LocalResource *local, struct stat *s) { + local->last_modified = s->st_mtime; + local->mode = s->st_mode & 07777; + local->uid = s->st_uid; + local->gid = s->st_gid; + local->size = s->st_size; +} + int sync_get_resource( CmdArgs *a, SyncDirectory *dir, @@ -887,6 +940,10 @@ if(ret == 0) { (*counter)++; + + if(sync_store_metadata(dir, tmp_path, local, res)) { + fprintf(stderr, "Cannot store metadata: %s\n", res->path); + } if(dir->trash && dir->backuppull) { move_to_trash(dir, local_path); @@ -918,13 +975,11 @@ if(local->etag) { free(local->etag); } + // set metadata from stat local->etag = strdup(etag); - local->last_modified = s.st_mtime; - local->size = s.st_size; + sync_set_metadata_from_stat(local, &s); local->skipped = FALSE; - - sync_store_tags(dir, tmp_path, local, res); } else { if(sys_unlink(tmp_path)) { fprintf(stderr, "Cannot remove tmp file: %s\n", tmp_path); @@ -1849,6 +1904,11 @@ if(db_res->last_modified == res->last_modified && db_res->size == res->size) { return 0; } + } else { + res->tags_updated = 1; + res->finfo_updated = 1; + res->xattr_updated = 1; + res->metadata_updated = 1; } return 1; } @@ -1954,6 +2014,66 @@ return equal; } +int sync_store_metadata(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res) { + int ret = 0; + + DavXmlNode *fileinfo = dav_get_property_ns(res, DAV_NS, "finfo"); + if(fileinfo) { + FileInfo f; + finfo_get_values(fileinfo, &f); + if(dir->metadata & FINFO_DATE == FINFO_DATE && f.date_set) { + // set mtime + struct utimbuf t; + t.actime = f.last_modified; + t.modtime = f.last_modified; + if(utime(path, &t)) { + fprintf(stderr, "utime failed for file: %s : %s\n", path, strerror(errno)); + ret = 1; + } + } + if(dir->metadata & FINFO_MODE == FINFO_MODE && f.mode_set) { + // set mode + if(chmod(path, f.mode)) { + fprintf(stderr, "chmod failed for file: %s : %s\n", path, strerror(errno)); + ret = 1; + } + } + } + + DavXmlNode *xattr_prop = dav_get_property_ns(res, DAV_NS, "xattributes"); + if(xattr_prop) { + XAttributes *xattr = xml_get_attributes(xattr_prop); + if(xattr) { + if(!sync_store_xattr(dir, path, xattr)) { + if(local->xattr_hash) { + free(local->xattr_hash); + } + local->xattr_hash = xattr->hash; + } + } + } + + if(sync_store_tags(dir, path, local, res)) { + ret = 1; + } + + return ret; +} + +int sync_store_xattr(SyncDirectory *dir, const char *path, XAttributes *xattr) { + for(int i=0;inattr;i++) { + sstr_t value = xattr->values[i]; + if(xattr_set(path, xattr->names[i], value.ptr, value.length)) { + fprintf( + stderr, + "Cannot store xattr '%s' for file: %s\n", + xattr->names[i], + path); + } + } + return 0; +} + int sync_store_tags(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res) { if(!dir->tagconfig) { return 0; @@ -1973,7 +2093,10 @@ UcxList *local_tags = sync_get_file_tags(dir, local, &tags_changed, NULL); if(tags_changed) { switch(dir->tagconfig->conflict) { - case TAG_NO_CONFLICT: + case TAG_NO_CONFLICT: { + store_tags = TRUE; + break; + } case TAG_KEEP_LOCAL: { store_tags = FALSE; break; @@ -2036,7 +2159,7 @@ int update = 1; if(local) { if(!local->tags_hash || strcmp(data_hash, local->tags_hash)) { - printf("update: %s\n", local->path); + //printf("update: %s\n", local->path); } else { update = 0; } @@ -2058,7 +2181,7 @@ } } else { if(local) { - printf("update: %s\n", local->path); + //printf("update: %s\n", local->path); } ret = xattr_remove(path, dir->tagconfig->xattr_name); }