implement hash based conflict resolution in dav-sync pull

Thu, 03 Oct 2019 12:00:25 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Thu, 03 Oct 2019 12:00:25 +0200
changeset 649
0f4c59ac8c74
parent 648
fefe4b6f1048
child 650
14e7101d7604

implement hash based conflict resolution in dav-sync pull

dav/scfg.c file | annotate | diff | comparison | revisions
dav/scfg.h file | annotate | diff | comparison | revisions
dav/sync.c file | annotate | diff | comparison | revisions
test/bin-test/test-dav-sync-hashing.sh file | annotate | diff | comparison | revisions
--- a/dav/scfg.c	Sun Sep 29 12:57:13 2019 +0200
+++ b/dav/scfg.c	Thu Oct 03 12:00:25 2019 +0200
@@ -438,6 +438,7 @@
     bool lockpush = false;
     bool hashing = false;
     bool store_hash = false;
+    bool pull_skip_hashing = false;
     //bool detect_copy = false;
     time_t lock_timeout = 0;
     uint32_t metadata = 0;
@@ -627,6 +628,7 @@
     dir->lockpush = lockpush;
     dir->hashing = hashing;
     dir->store_hash = store_hash;
+    dir->pull_skip_hashing = pull_skip_hashing;
     dir->lock_timeout = lock_timeout;
     dir->metadata = metadata;
     dir->splitconfig = splitconfig;
--- a/dav/scfg.h	Sun Sep 29 12:57:13 2019 +0200
+++ b/dav/scfg.h	Thu Oct 03 12:00:25 2019 +0200
@@ -100,6 +100,7 @@
     bool lockpush;
     bool hashing;
     bool store_hash;
+    bool pull_skip_hashing;
     uint32_t db_settings;
 } SyncDirectory;
 
--- a/dav/sync.c	Sun Sep 29 12:57:13 2019 +0200
+++ b/dav/sync.c	Thu Oct 03 12:00:25 2019 +0200
@@ -965,6 +965,7 @@
         fprintf(stderr, "Error: resource %s has no etag\n", res->path);
         return REMOTE_NO_CHANGE;
     }
+    char *hash = sync_get_content_hash(res);
     
     DavBool issplit = dav_get_property(res, "idav:split") ? TRUE : FALSE;
     if(issplit) {
@@ -1004,15 +1005,9 @@
         }
     } else if(local) {
         DavBool nochange = FALSE;
-        char *content_hash = sync_get_content_hash(res);
-        
         if(SYNC_SYMLINK(dir) && nullstrcmp(link, local->link_target)) {
             ret = REMOTE_CHANGE_LINK;
             nochange = TRUE;
-        } else if(content_hash && local->hash) {
-            if(!strcmp(content_hash, local->hash)) {
-                nochange = TRUE;
-            }
         } else if(local->etag) {
             sstr_t e = sstr(etag);
             if(sstrprefix(e, S("W/"))) {
@@ -1041,7 +1036,28 @@
     } else {
         ret = REMOTE_CHANGE_NEW;
     }
-    
+     
+    // if hashing is enabled we can compare the hash of the remote file
+    // with the local file to test if a file is really modified
+    if (!iscollection &&
+        !link &&
+        (ret == REMOTE_CHANGE_MODIFIED || ret == REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED) &&
+        exists &&
+        hash &&
+        !dir->pull_skip_hashing)
+    {
+        // because rehashing a file is slow, there is a config element for
+        // disabling this (pull-skip-hashing)
+        char *local_hash = util_file_hash(local_path);
+        if(local_hash) {
+            if(!strcmp(hash, local_hash)) {
+                ret = REMOTE_NO_CHANGE;
+            }
+        }
+        free(local_hash);
+    }
+    
+    // if a file is not modified, check if the metadata has changed
     while(ret == REMOTE_NO_CHANGE && local) {
         // check if tags have changed
         if(dir->tagconfig) {
@@ -2909,7 +2925,7 @@
         char *hash = sync_get_content_hash(remote);
         
         if(hash && res->hash && equal) {
-            // if requested, check if the local and remote are equal
+            // if requested, check if the local and remote res are equal
             if(!strcmp(hash, res->hash)) {
                 *equal = TRUE;
                 return 0;
--- a/test/bin-test/test-dav-sync-hashing.sh	Sun Sep 29 12:57:13 2019 +0200
+++ b/test/bin-test/test-dav-sync-hashing.sh	Thu Oct 03 12:00:25 2019 +0200
@@ -412,6 +412,7 @@
 rm -f tmp-sync/test2a/t13file1
 mv tmp-sync/test2a/t13file2 tmp-sync/test2a/t13file1
 
+sleep 2
 
 dav_sync_push test2a "test 13: push failed"
 # we can't check the exact output, because there are multiple valid ways

mercurial