diff -r 99ef8202cd82 -r e1a12762bf0a dav/sync.c --- a/dav/sync.c Sun Apr 07 10:44:29 2019 +0200 +++ b/dav/sync.c Sun Apr 07 13:08:50 2019 +0200 @@ -1595,7 +1595,7 @@ // check if a file with this hash already exists LocalResource *origin = ucx_map_cstr_get(db_hashes, hash); if(origin) { - local->origin = strdup(origin->path); + local->origin = local_resource_copy(origin, origin->path); // the file is a copied/moved file // check if the file is in the resources_map, because then // it still exists @@ -1732,39 +1732,50 @@ DavBool copy = TRUE; for(UcxList *elm=ls_copy;elm && !sync_shutdown;elm=elm->next) { LocalResource *local = elm->data; - DavResource *res = dav_resource_new(sn, local->origin); + int err = 0; - if(copy) { - printf("copy: %s -> %s\n", local->origin, local->path); - err = dav_copy_o(res, local->path, FALSE); - - if(!elm->next) { - // finished copy, begin move - elm->next = ls_move; - copy = FALSE; + DavResource *res = dav_resource_new(sn, local->path); + if(dav_exists(res)) { + printf("conflict: %s\n", local->path); + sync_skipped++; + } else { + DavResource *origin_res = dav_resource_new(sn, local->origin->path); + int origin_changed = remote_resource_is_changed( + sn, + dir, + db, + origin_res, + local->origin); + if(origin_changed) { + // upload with put + printf("put: %s\n", local->path); + err = sync_put_resource(dir, res, local, &sync_success); + } else { + printf("%s: %s -> %s\n", copy ? "copy":"move", local->origin->path, local->path); + err = sync_move_remote_resource( + dir, + origin_res, + local, + copy, + &sync_success); } - } else { - printf("move: %s -> %s\n", local->origin, local->path); - err = dav_move_o(res, local->path, FALSE); } if(err) { - if(sn->error == DAV_PRECONDITION_FAILED) { - printf("conflict: %s\n", local->path); - local->last_modified = 0; - local->skipped = TRUE; - sync_skipped++; - } else { - sync_error++; - print_resource_error(sn, res->path); - ret = -1; - error = 1; - } + sync_error++; + print_resource_error(sn, res->path); + ret = -1; + error = 1; } - dav_resource_free(res); LocalResource *dbres = ucx_map_cstr_remove(db->resources, local->path); ucx_map_cstr_put(db->resources, local->path, local); + + if(copy && !elm->next) { + // finished copy, begin move + elm->next = ls_move; + copy = FALSE; + } } // metadata updates @@ -2228,28 +2239,6 @@ } } -LocalResource* local_resource_copy(LocalResource *res) { - LocalResource *newres = calloc(1, sizeof(LocalResource)); - if(res->name) { - newres->name = strdup(res->name); - } - if(res->path) { - newres->path = strdup(res->path); - } - if(res->etag) { - newres->etag = strdup(res->etag); - } - newres->skipped = res->skipped; - newres->size = res->size; - newres->last_modified = res->last_modified; - newres->isdirectory = res->isdirectory; - if(res->tags_hash) { - newres->tags_hash = strdup(res->tags_hash); - } - newres->tags_updated = res->tags_updated; - return newres; -} - int local_resource_is_changed( SyncDirectory *dir, SyncDatabase *db, @@ -3406,6 +3395,78 @@ return ret; } +int sync_move_remote_resource( + SyncDirectory *dir, + DavResource *origin, + LocalResource *local, + DavBool copy, + int *counter) +{ + char *local_path = create_local_path(dir, local->path); + + SYS_STAT s; + if(sys_stat(local_path, &s)) { + fprintf(stderr, "Cannot stat file: %s\n", local_path); + perror(""); + free(local_path); + return -1; + } + free(local_path); + + int result = 0; + if(copy) { + result = dav_copy_o(origin, local->path, FALSE); + } else { + result = dav_move_o(origin, local->path, FALSE); + } + + if(result != 0) { + return result; + } + + // replace LocalResource with origin content + LocalResource *local_origin = local->origin; + local->origin = NULL; + char *path = strdup(local->path); + // TODO: free stuff before replacing it + memcpy(local, local_origin, sizeof(LocalResource)); + local->path = path; + + free(local_origin); // only free origin pointer + + // get new etag + DavResource *up_res = dav_get(origin->session, origin->path, "D:getetag"); + if(up_res) { + (*counter)++; + + // everything seems fine, we can update the local resource + char *etag = dav_get_string_property(up_res, "D:getetag"); + if(etag) { + if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') { + etag = etag + 2; + } + } + + if(local->etag) { + free(local->etag); + } + + if(etag) { + local->etag = strdup(etag); + } else { + local->etag = NULL; + } + + local->last_modified = s.st_mtime; + + dav_resource_free(up_res); + } else { + result = 1; + } + + return result; +} + int sync_delete_remote_resource( SyncDirectory *dir, DavSession *sn, @@ -3440,7 +3501,7 @@ } } - if(etag && !strcmp(etag, local_res->etag)) { + if(nullstrcmp(etag, local_res->etag)) { // local resource metadata == remote resource metadata // resource can be deleted printf("delete: %s\n", res->path);