# HG changeset patch # User Olaf Wintermann # Date 1553161874 -3600 # Node ID 5b9f20aa88c2d98187bb6c7cc9a38f0d17400e22 # Parent aeda4771497894a9d88211f0a9fc4758cb45a42d adds option to restore previous file versions diff -r aeda47714978 -r 5b9f20aa88c2 dav/sopt.c --- a/dav/sopt.c Wed Mar 20 13:20:38 2019 +0100 +++ b/dav/sopt.c Thu Mar 21 10:51:14 2019 +0100 @@ -91,6 +91,11 @@ optchar = 't'; break; } + case 'V': { + option = "version"; + optchar = 'V'; + break; + } case 'R': { ucx_map_cstr_put(a->options, "restore-removed", NOARG); break; @@ -99,8 +104,8 @@ ucx_map_cstr_put(a->options, "restore-modified", NOARG); break; } - case 'V': { - ucx_map_cstr_put(a->options, "versioning", NOARG); + case 'S': { + ucx_map_cstr_put(a->options, "snapshot", NOARG); } } } diff -r aeda47714978 -r 5b9f20aa88c2 dav/sync.c --- a/dav/sync.c Wed Mar 20 13:20:38 2019 +0100 +++ b/dav/sync.c Thu Mar 21 10:51:14 2019 +0100 @@ -72,6 +72,15 @@ va_end(ap); } +static DavPropName defprops[] = { + { "DAV:", "getetag" }, + { DAV_NS, "status" }, + { DAV_NS, "finfo" }, + { DAV_NS, "tags" }, + { DAV_NS, "xattributes" } +}; +static size_t numdefprops = 5; + /* * strcmp version that works with NULL pointers */ @@ -194,9 +203,10 @@ fprintf(stderr, "Commands:\n"); fprintf(stderr, " pull [-cldr] [-t ] \n"); - fprintf(stderr, " push [-cldrVRM] [-t ] \n"); - fprintf(stderr, " archive [-cldVRM] [-t ] \n"); - fprintf(stderr, " restore [-ldRM] [-s ] [file...]\n"); + fprintf(stderr, " push [-cldrSRM] [-t ] \n"); + fprintf(stderr, " archive [-cldSRM] [-t ] \n"); + fprintf(stderr, + " restore [-ldRM] [-V ] [-s ] [file...]\n"); fprintf(stderr, " resolve-conflicts \n"); fprintf(stderr, " delete-conflicts \n"); fprintf(stderr, " trash-info \n"); @@ -214,7 +224,8 @@ "Only sync files which have the specified tags\n"); fprintf(stderr, " -r " "Remove resources not matching the tag filter\n"); - fprintf(stderr, " -V Enable versioning\n"); + fprintf(stderr, " -V Restore specific version\n"); + fprintf(stderr, " -S Save previous file version\n"); fprintf(stderr, " -R Restore removed files\n"); fprintf(stderr, " -M Restore modified files\n"); fprintf(stderr, " -v Verbose output (all commands)\n\n"); @@ -684,7 +695,7 @@ } // download the resource - if(sync_get_resource(a, dir, res, db, &sync_success)) { + if(sync_get_resource(a, dir, res->path, res, db, &sync_success)) { fprintf(stderr, "resource download failed: %s\n", res->path); sync_error++; } @@ -908,12 +919,13 @@ int sync_get_resource( CmdArgs *a, SyncDirectory *dir, + const char *path, DavResource *res, SyncDatabase *db, int *counter) { - LocalResource *local = ucx_map_cstr_get(db->resources, res->path); - char *local_path = util_concat_path(dir->path, res->path); + LocalResource *local = ucx_map_cstr_get(db->resources, path); + char *local_path = util_concat_path(dir->path, path); char *etag = dav_get_string_property(res, "D:getetag"); SYS_STAT s; @@ -934,7 +946,7 @@ free(tmp_path); return -1; } - printf("get: %s\n", res->path); + printf("get: %s\n", path); if(dav_get_content(res, out, (dav_write_func)fwrite)) { ret = -1; } @@ -944,7 +956,7 @@ (*counter)++; if(sync_store_metadata(dir, tmp_path, local, res)) { - fprintf(stderr, "Cannot store metadata: %s\n", res->path); + fprintf(stderr, "Cannot store metadata: %s\n", path); } if(dir->trash && dir->backuppull) { @@ -970,7 +982,7 @@ if(!local) { // new local resource local = calloc(1, sizeof(LocalResource)); - local->path = strdup(res->path); + local->path = strdup(path); ucx_map_cstr_put(db->resources, local->path, local); } @@ -1177,7 +1189,7 @@ if(scfg_check_dir(dir)) { return -1; } - if(cmd_getoption(a, "versioning")) { + if(cmd_getoption(a, "snapshot")) { if(dir->versioning) { dir->versioning->always = TRUE; } else { @@ -1429,20 +1441,7 @@ for(UcxList *elm=ls_update;elm && !sync_shutdown;elm=elm->next) { LocalResource *local_res = elm->data; - DavResource *res = dav_resource_new(sn, local_res->path); - if(dir->tagconfig) { - DavPropName properties[] = { - {DAV_NS,"tags"}, - }; - if(dav_load_prop(res, properties, 1)) { - sync_error++; - print_resource_error(sn, res->path); - ret = -1; - error = 1; - continue; - } - } - + DavResource *res = dav_resource_new(sn, local_res->path); if(local_res->metadata_updated) { if(!sync_update_metadata(dir, sn, res, local_res)) { LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path); @@ -1535,6 +1534,14 @@ return -1; } + char *version = cmd_getoption(a, "version"); + if(version) { + if(a->argc != 1) { + fprintf(stderr, "If the -V option is enabled, only one file can be specified\n"); + return -1; + } + } + SyncDirectory *dir = NULL; UcxMap *files = NULL; if(syncdir) { @@ -1684,17 +1691,33 @@ UCX_FOREACH(elm, resources) { LocalResource *resource = elm->data; - DavResource *res = dav_get(sn, resource->path, "D:getetag,idav:status,idav:finfo,idav:xattributes"); + DavResource *res = dav_get(sn, resource->path, "D:getetag,idav:status,idav:version-collection,idav:finfo,idav:xattributes"); if(!res) { printf("skip: %s\n", resource->path); continue; - //continue; } char *status = dav_get_string_property(res, "idav:status"); if(status && !strcmp(status, "broken")) { + fprintf(stderr, "Resource %s broken\n", res->path); continue; } + DavResource *vres = NULL; + if(version) { + if(dir->versioning->type == VERSIONING_SIMPLE) { + vres = versioning_simple_find(res, version); + } else if(dir->versioning->type == VERSIONING_DELTAV) { + vres = versioning_deltav_find(res, version); + } + if(!vres) { + fprintf(stderr, "Cannot find specified version for resource %s\n", res->path); + ret = 1; + break; + } + } else { + vres = res; + } + // download the resource if(!sync_shutdown) { if(resource->isdirectory) { @@ -1706,7 +1729,7 @@ } free(local_path); } else { - if(sync_get_resource(a, dir, res, db, &sync_success)) { + if(sync_get_resource(a, dir, res->path, vres, db, &sync_success)) { fprintf(stderr, "sync_get_resource failed for resource: %s\n", res->path); sync_error++; } @@ -1746,7 +1769,7 @@ sync_error, str_error); } - return 0; + return ret; } UcxList* local_scan(SyncDirectory *dir, SyncDatabase *db) { @@ -2047,6 +2070,58 @@ } } +DavResource *versioning_simple_find(DavResource *res, const char *version) { + char *vcol_href = dav_get_string_property_ns(res, DAV_NS, VERSION_PATH_PROPERTY); + if(!vcol_href) { + return NULL; + } + DavResource *vcol = dav_resource_new_href(res->session, vcol_href); + if(!vcol) { + return NULL; + } + + + if(dav_load_prop(vcol, defprops, numdefprops)) { + print_resource_error(res->session, vcol->path); + dav_resource_free(vcol); + return NULL; + } + + DavResource *ret = NULL; + DavResource *child = vcol->children; + while(child) { + DavResource *next = child->next; + if(!strcmp(child->name, version)) { + ret = child; + } else { + dav_resource_free(child); + } + child = next; + } + dav_resource_free(vcol); + + return ret; +} + +// TODO: remove code dup (main.c: find_version) +DavResource* versioning_deltav_find(DavResource *res, const char *version) { + DavResource *list = dav_versiontree(res, "D:getetag,idav:status,idav:finfo,idav:xattributes,idav:tags"); + DavResource *ret = NULL; + while(list) { + DavResource *next = list->next; + if(!ret) { + char *vname = dav_get_string_property(list, "D:version-name"); + if(vname && !strcmp(vname, version)) { + ret = list; + } + } + if(list != ret) { + dav_resource_free(list); + } + list = next; + } + return ret; +} int sync_set_status(DavResource *res, char *status) { DavResource *resource = dav_resource_new(res->session, res->path); diff -r aeda47714978 -r 5b9f20aa88c2 dav/sync.h --- a/dav/sync.h Wed Mar 20 13:20:38 2019 +0100 +++ b/dav/sync.h Thu Mar 21 10:51:14 2019 +0100 @@ -103,6 +103,7 @@ int sync_get_resource( CmdArgs *a, SyncDirectory *dir, + const char *path, DavResource *res, SyncDatabase *db, int *counter); @@ -111,6 +112,7 @@ void rename_conflict_file(SyncDirectory *dir, SyncDatabase *db, char *path); char* create_tmp_download_path(char *path); void move_to_trash(SyncDirectory *dir, char *path); + 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); @@ -131,6 +133,9 @@ int resource_pathlen_cmp(LocalResource *res1, LocalResource *res2, void *n); +DavResource *versioning_simple_find(DavResource *res, const char *version); +DavResource *versioning_deltav_find(DavResource *res, const char *version); + int sync_set_status(DavResource *res, char *status); int sync_remove_status(DavResource *res); UcxBuffer* sync_get_file_tag_data(SyncDirectory *dir, LocalResource *res);