# HG changeset patch # User Olaf Wintermann # Date 1553019288 -3600 # Node ID d0e37224eba14b7230d7d49eddf7902c0e0dee4d # Parent e3c0440bd599a09b2878f28c9303848842a84cd5 adds possibility to restore specific files diff -r e3c0440bd599 -r d0e37224eba1 dav/finfo.c --- a/dav/finfo.c Sun Mar 17 18:11:31 2019 +0100 +++ b/dav/finfo.c Tue Mar 19 19:14:48 2019 +0100 @@ -174,6 +174,8 @@ attributes = calloc(1, sizeof(XAttributes)); attributes->hash = hash ? strdup(hash) : NULL; attributes->nattr = count; + attributes->names = calloc(count, sizeof(char*)); + attributes->values = calloc(count, sizeof(sstr_t)); int i=0; UCX_FOREACH(elm, names) { attributes->names[i] = elm->data; diff -r e3c0440bd599 -r d0e37224eba1 dav/sync.c --- a/dav/sync.c Sun Mar 17 18:11:31 2019 +0100 +++ b/dav/sync.c Tue Mar 19 19:14:48 2019 +0100 @@ -194,7 +194,7 @@ fprintf(stderr, " pull [-cldr] [-t ] \n"); fprintf(stderr, " push [-cldrVRM] [-t ] \n"); fprintf(stderr, " archive [-cldVRM] [-t ] \n"); - fprintf(stderr, " restore [-ld] \n"); + fprintf(stderr, " restore [-ld] [-s ] [file...]\n"); fprintf(stderr, " resolve-conflicts \n"); fprintf(stderr, " delete-conflicts \n"); fprintf(stderr, " trash-info \n"); @@ -1526,9 +1526,47 @@ } int cmd_restore(CmdArgs *a) { - SyncDirectory *dir = scfg_get_dir(a->argv[0]); + char *syncdir = cmd_getoption(a, "syncdir"); + + if(!syncdir && a->argc == 0) { + fprintf(stderr, "No syncdir or files specified\n"); + return -1; + } + + SyncDirectory *dir = NULL; + UcxMap *files = NULL; + if(syncdir) { + dir = scfg_get_dir(syncdir); + } + + LocalResource nres; + if(a->argc > 0) { + files = ucx_map_new(a->argc+8); + // get all specified files and check the syncdir + SyncDirectory *sd = NULL; + for(int i=0;iargc;i++) { + SyncFile f; + int err = sync_get_file(a, a->argv[i], &f, FALSE); + if(err) { + sync_print_get_file_err(a->argv[i], err); + return 1; + } + if(!sd) { + sd = f.dir; + } else { + if(f.dir != sd) { + fprintf(stderr, "Not all files are in the same syncdir\n"); + return 1; + } + } + + ucx_map_cstr_put(files, f.path, &nres); + } + dir = sd; + } + if(!dir) { - fprintf(stderr, "Unknown sync dir: %s\n", a->argv[0]); + fprintf(stderr, "Unknown sync dir: %s\n", syncdir); return -1; } if(scfg_check_dir(dir)) { @@ -1553,9 +1591,13 @@ // iterate over all db resources and check if any resource is // modified or deleted - UcxMapIterator i = ucx_map_iterator(db->resources); + UcxMapIterator i = ucx_map_iterator(files ? files : db->resources); LocalResource *resource; UCX_MAP_FOREACH(key, resource, i) { + if(resource == &nres) { + resource = ucx_map_get(db->resources, key); + } + char *file_path = util_concat_path(dir->path, resource->path); SYS_STAT s; if(sys_stat(file_path, &s)) { @@ -1570,8 +1612,12 @@ modified = ucx_list_prepend(modified, resource); } } - + free(file_path); + } + + if(files) { + ucx_map_free(files); } int ret = 0; @@ -1618,7 +1664,7 @@ UCX_FOREACH(elm, resources) { LocalResource *resource = elm->data; - DavResource *res = dav_get(sn, resource->path, "idav:status,D:getetag"); + DavResource *res = dav_get(sn, resource->path, "D:getetag,idav:status,idav:finfo,idav:xattributes"); char *status = dav_get_string_property(res, "idav:status"); if(status && !strcmp(status, "broken")) { @@ -2104,6 +2150,7 @@ case TAG_KEEP_REMOTE: { store_tags = TRUE; local->tags_updated = FALSE; + break; } case TAG_MERGE: { UcxList *new_tags = merge_tags(local_tags, tags); @@ -2183,10 +2230,15 @@ if(local) { //printf("update: %s\n", local->path); } - ret = xattr_remove(path, dir->tagconfig->xattr_name); + // ignore errors on remove + xattr_remove(path, dir->tagconfig->xattr_name); } } + if(!ret) { + local->tags_updated = 0; + } + return ret; } @@ -3124,9 +3176,9 @@ int ret = 0; char *path = args->argv[0]; - int err = sync_get_file(args, path, NULL, &file); + int err = sync_get_file(args, path, &file, TRUE); if(err) { - fprintf(stderr, "err: %d\n", err); // TODO: print nice err msg + sync_print_get_file_err(path, err); return -1; } @@ -3214,7 +3266,7 @@ return ret; } -static int isfileindir(SyncDirectory *dir, const char *path, SyncFile *f) { +int isfileindir(SyncDirectory *dir, const char *path, SyncFile *f) { char *fullpath; if(path[0] != '/') { size_t wdlen = 256; @@ -3257,13 +3309,15 @@ return 1; } -int sync_get_file(CmdArgs *args, const char *path, const char *dir, SyncFile *f) { - SYS_STAT s; - if(sys_stat(path, &s)) { - switch(errno) { - case EACCES: return 2; - case ENOENT: return 1; - default: return 3; +int sync_get_file(CmdArgs *args, const char *path, SyncFile *f, DavBool dostat) { + if(dostat) { + SYS_STAT s; + if(sys_stat(path, &s)) { + switch(errno) { + case EACCES: return 2; + case ENOENT: return 1; + default: return 3; + } } } @@ -3301,6 +3355,17 @@ return 0; } +void sync_print_get_file_err(const char *path, int err) { + switch(err) { + case 1: fprintf(stderr, "File %s: not found\n", path); break; + case 2: fprintf(stderr, "File %s: permission denied\n"); break; + case 3: fprintf(stderr, "File %s: stat failed: %s\n", path, strerror(errno)); break; + case 4: fprintf(stderr, "File %s is not in any syncdir\n"); break; + case 5: fprintf(stderr, "File %s is in multiple syncdirs\n"); break; + case 6: fprintf(stderr, "Syncdir not found\n"); break; + } +} + int cmd_add_directory(CmdArgs *args) { if(!get_repositories()) { diff -r e3c0440bd599 -r d0e37224eba1 dav/sync.h --- a/dav/sync.h Sun Mar 17 18:11:31 2019 +0100 +++ b/dav/sync.h Tue Mar 19 19:14:48 2019 +0100 @@ -183,7 +183,10 @@ * 5: file is in multiple syncdirs * 6: syncdir not found */ -int sync_get_file(CmdArgs *args, const char *path, const char *dir, SyncFile *f); +int sync_get_file(CmdArgs *args, const char *path, SyncFile *f, DavBool dostat); +void sync_print_get_file_err(const char *path, int err); + +int isfileindir(SyncDirectory *dir, const char *path, SyncFile *f); int cmd_add_directory(CmdArgs *args); int cmd_list_dirs();