improved dav-sync data-loss prevention

Sat, 03 Oct 2015 14:36:12 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 03 Oct 2015 14:36:12 +0200
changeset 145
82475dc12dd4
parent 144
c2c02c9b3be4
child 146
e48048334602

improved dav-sync data-loss prevention

dav/scfg.c file | annotate | diff | comparison | revisions
dav/scfg.h file | annotate | diff | comparison | revisions
dav/sync.c file | annotate | diff | comparison | revisions
dav/sync.h file | annotate | diff | comparison | revisions
libidav/davqlexec.c file | annotate | diff | comparison | revisions
--- 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 <max-retry> 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 {
--- 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();
--- 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++) {
--- 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);
--- 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] == '%') {

mercurial