diff -r 487645580b5e -r ab159748055c dav/sync.c --- a/dav/sync.c Sat Nov 23 17:49:18 2019 +0100 +++ b/dav/sync.c Sun Nov 24 12:40:28 2019 +0100 @@ -969,6 +969,8 @@ SyncDirectory *dir, SyncDatabase *db) { + DavBool update_db = FALSE; + char *etag = dav_get_string_property(res, "D:getetag"); if(!etag) { fprintf(stderr, "Error: resource %s has no etag\n", res->path); @@ -1017,6 +1019,19 @@ if(SYNC_SYMLINK(dir) && nullstrcmp(link, local->link_target)) { ret = REMOTE_CHANGE_LINK; nochange = TRUE; + + if(local->link_target) { + LocalResource *local2 = local_resource_new(dir, db, local->path); + if(type == REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED && nullstrcmp(local->link_target, local2->link_target)) { + ret = REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED; + } + local_resource_free(local2); + + if(!nullstrcmp(link, local->link_target)) { + ret = REMOTE_NO_CHANGE; + update_db = TRUE; + } + } } else if(issplit && local->hash && hash) { if(!strcmp(local->hash, hash)) { // resource is already up-to-date on the client @@ -1040,11 +1055,26 @@ ret = type; } } else if(link) { + // new file is a link + ret = REMOTE_CHANGE_LINK; + if(exists && type == REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED) { - ret = REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED; - } else { - ret = REMOTE_CHANGE_LINK; - } + // a file with the same name already exists + // if it is a link, compare the targets + LocalResource *local2 = local_resource_new(dir, db, res->path); + if(local2) { + if(local2->link_target) { + if(strcmp(link, local2->link_target)) { + ret = REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED; + } + } else { + ret = REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED; + } + + local_resource_free(local2); + } + } + } else if(exists) { ret = type; } else { @@ -1053,7 +1083,6 @@ // if hashing is enabled we can compare the hash of the remote file // with the local file to test if a file is really modified - DavBool update_db = FALSE; char *update_hash = NULL; if (!iscollection && !link && @@ -1155,6 +1184,10 @@ if(!local->hash) { local->hash = update_hash; } // else: hash already updated + if(link) { + nullfree(local->link_target); + local->link_target = link; + } } free(local_path); @@ -2210,6 +2243,7 @@ sync_error++; } else { DavBool equal = FALSE; + DavBool res_conflict = FALSE; int changed = remote_resource_is_changed(sn, dir, db, res, local_res, &equal); if(equal) { char *etag = dav_get_string_property(res, "D:getetag"); @@ -2231,6 +2265,14 @@ local_res->hash = NULL; local_res->skipped = TRUE; sync_conflict++; + + if(local_res->link_target) { + free(local_res->link_target); + local_res->link_target = local_res->link_target_db; + local_res->link_target_db = NULL; + } + + res_conflict = TRUE; } else { if(local_res->link_target) { printf( @@ -2252,7 +2294,11 @@ if(!err) { LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path); - ucx_map_cstr_put(db->resources, local_res->path, local_res); + // in case of a conflict, don't store the resource + // in the db, if it is new + if(!res_conflict || dbres) { + ucx_map_cstr_put(db->resources, local_res->path, local_res); + } } } @@ -2847,6 +2893,9 @@ if(db_res->hash) { res->prev_hash = strdup(db_res->hash); } + if(db_res->link_target) { + res->link_target_db = db_res->link_target; + } // if the resource is splitted, copy the part info to the new // LocalResource obj, because we need it later @@ -3005,11 +3054,21 @@ return 1; } + char *link = dav_get_string_property_ns(remote, DAV_PROPS_NS, "link"); + int ret = 0; if(err == 0) { char *etag = dav_get_string_property(remote, "D:getetag"); char *hash = sync_get_content_hash(remote); + if(res->link_target_db || link) { + ret = nullstrcmp(res->link_target_db, link); + if(ret && equal) { + *equal = !nullstrcmp(res->link_target, link); + } + return ret; + } + if(hash && res->hash && equal) { // if requested, check if the local and remote res are equal if(!strcmp(hash, res->hash)) {