diff -r 2f019a4bc78a -r 761dc4867208 dav/sync.c --- a/dav/sync.c Wed Jul 11 15:46:15 2018 +0200 +++ b/dav/sync.c Wed Jul 11 16:40:07 2018 +0200 @@ -171,8 +171,8 @@ fprintf(stderr, "Commands:\n"); fprintf(stderr, " pull [-cldr] [-t ] \n"); - fprintf(stderr, " push [-cldr] [-t ] \n"); - fprintf(stderr, " archive [-cld] [-t ] \n"); + fprintf(stderr, " push [-cldrDM] [-t ] \n"); + fprintf(stderr, " archive [-cldDM] [-t ] \n"); fprintf(stderr, " resolve-conflicts \n"); fprintf(stderr, " delete-conflicts \n"); fprintf(stderr, " trash-info \n"); @@ -190,6 +190,8 @@ "Only sync files which have the specified tags\n"); fprintf(stderr, " -r " "Remove resources not matching the tag filter\n"); + fprintf(stderr, " -D restore deleted files\n"); + fprintf(stderr, " -M restore modified files\n"); fprintf(stderr, " -v verbose output (all commands)\n\n"); fprintf(stderr, "Config commands:\n"); @@ -359,6 +361,23 @@ } +void res2map(DavResource *root, UcxMap *map) { + UcxList *stack = ucx_list_prepend(NULL, root->children); + while(stack) { + DavResource *res = stack->data; + stack = ucx_list_remove(stack, stack); + + while(res) { + ucx_map_cstr_put(map, res->path, res); + + if(res->children) { + stack = ucx_list_prepend(stack, res->children); + } + res = res->next; + } + } +} + int cmd_pull(CmdArgs *a) { if(a->argc != 1) { fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many"); @@ -997,7 +1016,12 @@ curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr); } - DavResource *root = dav_query(sn, "select - from / with depth = 0"); + DavBool restore_deleted = cmd_getoption(a, "restore-deleted") ? 1 : 0; + DavBool restore_modified = cmd_getoption(a, "restore-modified") ? 1 : 0; + DavBool restore = restore_deleted || restore_modified; + int depth = restore ? -1 : 0; + + DavResource *root = dav_query(sn, "select D:getetag,idav:status from / with depth = %d", depth); if(!root) { print_resource_error(sn, "/"); dav_session_destroy(sn); @@ -1005,6 +1029,12 @@ return -1; } + UcxMap *svrres = NULL; + if(restore) { + svrres = ucx_map_new(1024); + res2map(root, svrres); + } + int cdt = cmd_getoption(a, "conflict") ? 0 : 1; // conflict detection // lock repository @@ -1083,7 +1113,13 @@ } // upload every changed file - int is_changed = local_resource_is_changed(dir, db, local_res); + int is_changed = local_resource_is_changed( + dir, + db, + local_res, + svrres, + restore_deleted, + restore_modified); if (is_changed || local_res->tags_updated) { DavResource *res = dav_resource_new(sn, local_res->path); if(!res) { @@ -1373,10 +1409,31 @@ return newres; } -int local_resource_is_changed(SyncDirectory *dir, SyncDatabase *db, LocalResource *res) { +int local_resource_is_changed( + SyncDirectory *dir, + SyncDatabase *db, + LocalResource *res, + UcxMap *svrres, + DavBool restore_deleted, + DavBool restore_modified) +{ LocalResource *db_res = ucx_map_cstr_get(db->resources, res->path); res->tags_updated = 0; if(db_res) { + if(svrres) { + DavResource *remote = ucx_map_cstr_get(svrres, res->path); + if(restore_deleted && !remote) { + return 1; + } + if(!res->isdirectory && restore_modified && remote) { + char *etag = dav_get_string_property(remote, "D:getetag"); + if(!etag || (db_res->etag && strcmp(etag, db_res->etag))) { + res->restore = TRUE; + return 1; + } + } + } + res->tags_updated = db_res->tags_updated; if(db_res->etag) { res->etag = strdup(db_res->etag); @@ -1415,6 +1472,10 @@ SyncDatabase *db, LocalResource *res) { + if(res->restore) { + return 0; + } + DavResource *remote = dav_get(sn, res->path, "D:getetag"); int ret = 0; if(remote) {