# HG changeset patch # User Olaf Wintermann # Date 1443875772 -7200 # Node ID 82475dc12dd43991d52eb131f5b9f43e21d986a3 # Parent c2c02c9b3be420820c20a38bb7eed93e5600cd17 improved dav-sync data-loss prevention diff -r c2c02c9b3be4 -r 82475dc12dd4 dav/scfg.c --- a/dav/scfg.c Sat Oct 03 13:33:15 2015 +0200 +++ b/dav/scfg.c Sat Oct 03 14:36:12 2015 +0200 @@ -95,6 +95,8 @@ char *database = NULL; UcxList *include = NULL; UcxList *exclude = NULL; + int max_retry = DAV_MAX_RETRY; + bool backuppull = false; node = node->children; while(node) { @@ -118,6 +120,16 @@ include = add_regex_pattern(include, value); } else if(xstreq(node->name, "exclude")) { exclude = add_regex_pattern(exclude, value); + } else if(xstreq(node->name, "max-retry")) { + int64_t i; + if(util_strtoint(value, &i)) { + max_retry = (int)i; + } else { + fprintf(stderr, "Warnung: sync.xml: integer value " + "expected in element\n"); + } + } else if(xstreq(node->name, "backup-on-pull")) { + backuppull = util_getboolean(value); } } node = node->next; @@ -146,7 +158,8 @@ dir->collection = collection ? strdup(collection) : NULL; dir->repository = strdup(repository); dir->database = strdup(database); - dir->max_retry = DAV_MAX_RETRY; + dir->max_retry = max_retry; + dir->backuppull = backuppull; if (include) { dir->include = include; } else { diff -r c2c02c9b3be4 -r 82475dc12dd4 dav/scfg.h --- a/dav/scfg.h Sat Oct 03 13:33:15 2015 +0200 +++ b/dav/scfg.h Sat Oct 03 14:36:12 2015 +0200 @@ -50,6 +50,7 @@ UcxList *include; UcxList *exclude; int max_retry; + bool backuppull; } SyncDirectory; int load_sync_config(); diff -r c2c02c9b3be4 -r 82475dc12dd4 dav/sync.c --- a/dav/sync.c Sat Oct 03 13:33:15 2015 +0200 +++ b/dav/sync.c Sat Oct 03 14:36:12 2015 +0200 @@ -268,7 +268,7 @@ int exists = 1; if(stat(local_path, &s)) { // Ignore the fact, that the file is locally removed. If the - // server has an updated version, we readd the file or the + // server has an updated version, we read the file or the // next push will delete it on the server. if(errno != ENOENT) { fprintf(stderr, "Cannot stat file: %s\n", local_path); @@ -308,16 +308,23 @@ } int ret = 0; + char *tmp_path = create_tmp_download_path(local_path); if(res->iscollection) { mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; if(util_mkdir(local_path, mode) && errno != EEXIST) { ret = -1; } } else { - FILE *out = fopen(local_path, "wb"); + if(!tmp_path) { + fprintf(stderr, "Cannot create tmp path for %s\n", local_path); + free(local_path); + return -1; + } + FILE *out = fopen(tmp_path, "wb"); if(!out) { fprintf(stderr, "Cannot open output file: %s\n", local_path); free(local_path); + free(tmp_path); return -1; } printf("get: %s\n", res->path); @@ -326,11 +333,27 @@ } fclose(out); - if(stat(local_path, &s)) { - fprintf(stderr, "Cannot stat file: %s\n", local_path); - } - if(ret == 0) { + if(dir->trash && dir->backuppull) { + move_to_trash(dir, local_path); + } + if(rename(tmp_path, local_path)) { + fprintf( + stderr, + "Cannot rename file %s to %s\n", + tmp_path, + local_path); + perror(""); + free(tmp_path); + free(local_path); + return -1; + } + + if(stat(local_path, &s)) { + fprintf(stderr, "Cannot stat file: %s\n", local_path); + perror(""); + } + if(!local) { // new local resource local = calloc(1, sizeof(LocalResource)); @@ -345,9 +368,14 @@ local->etag = etag; local->last_modified = s.st_mtime; local->size = s.st_size; + } else { + if(unlink(tmp_path)) { + fprintf(stderr, "Cannot remove tmp file: %s\n", tmp_path); + } } } + free(tmp_path); free(local_path); return ret; } @@ -411,6 +439,31 @@ free(parent); } +char* create_tmp_download_path(char *path) { + char *new_path = NULL; + char *parent = util_parent_path(path); + for (int i=0;;i++) { + sstr_t np = ucx_asprintf( + ucx_default_allocator(), + "%sdownload%d-%s", + parent, + i, + util_resource_name(path)); + + struct stat s; + if(stat(np.ptr, &s)) { + if(errno == ENOENT) { + new_path = np.ptr; + } + break; + } + free(np.ptr); + }; + + free(parent); + return new_path; +} + void move_to_trash(SyncDirectory *dir, char *path) { char *new_path = NULL; for (int i=0;;i++) { diff -r c2c02c9b3be4 -r 82475dc12dd4 dav/sync.h --- a/dav/sync.h Sat Oct 03 13:33:15 2015 +0200 +++ b/dav/sync.h Sat Oct 03 14:36:12 2015 +0200 @@ -50,6 +50,7 @@ int sync_get_resource(CmdArgs *a, SyncDirectory *dir, DavResource *res, SyncDatabase *db); void sync_remove_local_resource(SyncDirectory *dir, LocalResource *res); void rename_local_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); diff -r c2c02c9b3be4 -r 82475dc12dd4 libidav/davqlexec.c --- a/libidav/davqlexec.c Sat Oct 03 13:33:15 2015 +0200 +++ b/libidav/davqlexec.c Sat Oct 03 14:36:12 2015 +0200 @@ -592,6 +592,7 @@ sstr_t src = expr->srctext; switch(expr->type) { + default: break; case DAVQL_NUMBER: { cmd.type = DAVQL_CMD_INT; if(src.ptr[0] == '%') {