# HG changeset patch # User Olaf Wintermann # Date 1554635330 -7200 # Node ID e1a12762bf0a9685f3385f959dcaff318531c125 # Parent 99ef8202cd82d4cab8df941f237f7e7698d54520 improve copy/move stability and db update diff -r 99ef8202cd82 -r e1a12762bf0a dav/db.c --- a/dav/db.c Sun Apr 07 10:44:29 2019 +0200 +++ b/dav/db.c Sun Apr 07 13:08:50 2019 +0200 @@ -654,6 +654,64 @@ free(res); } +char* nullstrdup(const char *s) { + return s ? strdup(s) : NULL; +} + +LocalResource* local_resource_copy(LocalResource *src, const char *new_path) { + LocalResource *newres = calloc(1, sizeof(LocalResource)); + newres->path = strdup(new_path); + newres->etag = nullstrdup(src->etag); + newres->hash = nullstrdup(src->hash); + newres->last_modified = src->last_modified; + newres->mode = src->mode; + newres->uid = src->uid; + newres->gid = src->gid; + newres->size = src->size; + newres->isdirectory = src->isdirectory; + newres->skipped = src->skipped; + + if(src->xattr) { + XAttributes *xattr = calloc(1, sizeof(XAttributes)); + xattr->hash = nullstrdup(src->xattr->hash); + xattr->nattr = src->xattr->nattr; + xattr->names = calloc(xattr->nattr, sizeof(char*)); + xattr->values = calloc(xattr->nattr, sizeof(sstr_t)); + for(int i=0;inattr;i++) { + xattr->names[i] = strdup(src->xattr->names[i]); + xattr->values[i] = sstrdup(src->xattr->values[i]); + } + newres->xattr = xattr; + } + + newres->tags_hash = nullstrdup(src->tags_hash); + newres->xattr_hash = nullstrdup(src->xattr_hash); + newres->remote_tags_hash = nullstrdup(src->remote_tags_hash); + + if(src->parts) { + newres->numparts = src->numparts; + newres->parts = calloc(src->numparts, sizeof(FilePart)); + for(int i=0;inumparts;i++) { + FilePart s = src->parts[i]; + FilePart p; + p.block = s.block; + p.hash = nullstrdup(s.hash); + p.etag = nullstrdup(s.etag); + newres->parts[i] = p; + } + } + + newres->blocksize = src->blocksize; + + newres->tags_updated = src->tags_updated; + newres->finfo_updated = src->finfo_updated; + newres->xattr_updated = src->xattr_updated; + newres->metadata_updated = src->metadata_updated; + + return newres; + +} + void filepart_free(FilePart *part) { if(part->etag) { free(part->etag); diff -r 99ef8202cd82 -r e1a12762bf0a dav/db.h --- a/dav/db.h Sun Apr 07 10:44:29 2019 +0200 +++ b/dav/db.h Sun Apr 07 13:08:50 2019 +0200 @@ -82,7 +82,7 @@ DavBool restore; DavBool isnew; - char *origin; + LocalResource *origin; }; struct FilePart { @@ -102,6 +102,8 @@ void local_resource_free(LocalResource *res); +LocalResource* local_resource_copy(LocalResource *src, const char *new_path); + void filepart_free(FilePart *part); UcxMap* create_hash_index(SyncDatabase *db); 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); diff -r 99ef8202cd82 -r e1a12762bf0a dav/sync.h --- a/dav/sync.h Sun Apr 07 10:44:29 2019 +0200 +++ b/dav/sync.h Sun Apr 07 13:08:50 2019 +0200 @@ -116,7 +116,6 @@ UcxList* local_scan(SyncDirectory *dir, SyncDatabase *db); UcxList* read_changes(SyncDirectory *dir, SyncDatabase *db); LocalResource* local_resource_new(SyncDirectory *dir, SyncDatabase *db, char *path, int *isdir); -LocalResource* local_resource_copy(LocalResource *res); int local_resource_is_changed( SyncDirectory *dir, SyncDatabase *db, @@ -153,6 +152,12 @@ LocalResource *local, int *counter); int sync_mkdir(SyncDirectory *dir, DavResource *res, LocalResource *local); +int sync_move_remote_resource( + SyncDirectory *dir, + DavResource *origin, + LocalResource *local, + DavBool copy, + int *counter); int sync_delete_remote_resource(SyncDirectory *dir, DavSession *sn, LocalResource *res, int *counter, UcxList **cols); MetadataHashes sync_set_metadata_properties( SyncDirectory *dir,