diff -r af91d3c96994 -r 8c700eae3eb8 dav/sync.c --- a/dav/sync.c Sat Apr 06 14:25:07 2019 +0200 +++ b/dav/sync.c Sun Apr 07 09:07:33 2019 +0200 @@ -1496,15 +1496,23 @@ DavBool remove_file = cmd_getoption(a, "remove") ? 1 : 0; + UcxMap *db_hashes = NULL; + if(dir->hashing) { + db_hashes = create_hash_index(db); + } + int sync_success = 0; int sync_delete = 0; int sync_skipped = 0; int sync_error = 0; - UcxList *ls_put = NULL; + UcxList *ls_new = NULL; + UcxList *ls_modified = NULL; UcxList *ls_conflict = NULL; UcxList *ls_update = NULL; UcxList *ls_delete = NULL; + UcxList *ls_move = NULL; + UcxList *ls_copy = NULL; // upload all changed files //UcxList *resources = cmd_getoption(a, "read") ? @@ -1528,7 +1536,7 @@ } } - // we need a fast file lookup map later + // we need a fast file lookup map later to detect deleted files ucx_map_cstr_put(resources_map, local_res->path, local_res); // dynamic tag filter @@ -1558,12 +1566,58 @@ restore_removed, restore_modified); if(is_changed) { - ls_put = ucx_list_append(ls_put, local_res); + if(local_res->isnew) { + ls_new = ucx_list_append(ls_new, local_res); + } else { + ls_modified = ucx_list_append(ls_modified, local_res); + } } else if(local_res->metadata_updated) { ls_update = ucx_list_append(ls_update, local_res); } } + if(dir->hashing) { + // calculate hashes of all new files and check if a file + // was moved or is a copy + UcxList *elm = ls_new; + while(elm) { + LocalResource *local = elm->data; + UcxList *prev = elm->prev; + UcxList *next = elm->next; + char *local_path = util_concat_path(dir->path, local->path); + char *hash = util_file_hash(local_path); + // 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); + // the file is a copied/moved file + // check if the file is in the resources_map, because then + // it still exists + if(ucx_map_cstr_get(resources_map, origin->path)) { + ls_copy = ucx_list_append(ls_copy, local); + } else { + ls_move = ucx_list_append(ls_move, local); + // put file in resources_map to prevent deletion + ucx_map_cstr_put(resources_map, origin->path, local); + } + // remove list elemend from ls_new + if(prev) { + prev->next = next; + } else { + ls_new = next; + } + if(next) { + next->prev = prev; + } + } + + free(hash); + free(local_path); + + elm = next; + } + } + // find all deleted files and cleanup the database UcxMapIterator i = ucx_map_iterator(db->resources); LocalResource *local; @@ -1585,7 +1639,7 @@ if(!ucx_map_get(resources_map, key)) { // The current LocalResource is in the database but doesn't exist // in the filesystem anymore. This means the file was deleted - // and should be deleted on server + // and should be deleted on the server if(!archive) { ls_delete = ucx_list_append(ls_delete, local); } else { @@ -1605,9 +1659,11 @@ // // upload changed files + ls_modified = ucx_list_concat(ls_new, ls_modified); + int ret = 0; int error = 0; - for(UcxList *elm=ls_put;elm && !sync_shutdown;elm=elm->next) { + for(UcxList *elm=ls_modified;elm && !sync_shutdown;elm=elm->next) { LocalResource *local_res = elm->data; DavResource *res = dav_resource_new(sn, local_res->path); @@ -2254,6 +2310,7 @@ res->finfo_updated = 1; res->xattr_updated = 1; res->metadata_updated = 1; + res->isnew = 1; } return 1; } @@ -3267,6 +3324,14 @@ local->etag = NULL; } + if(!issplit && dir->hashing) { + if(local->hash) { + free(local->hash); + } + // TODO: calculate hash on upload + local->hash = util_file_hash(local_path); + } + if(dav_get_string_property(up_res, "idav:status")) { sync_remove_status(up_res); }