fix dav-sync copy with enabled metadata sync

Sat, 26 Oct 2019 11:32:27 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 26 Oct 2019 11:32:27 +0200
changeset 672
4bfe452a2665
parent 671
5256d7eb69e7
child 673
8e7e56cfc103

fix dav-sync copy with enabled metadata sync

dav/sync.c file | annotate | diff | comparison | revisions
dav/sync.h file | annotate | diff | comparison | revisions
test/bin-test/test-dav-sync-metadata2.sh file | annotate | diff | comparison | revisions
test/bin-test/test-dav-sync-metadata3.sh file | annotate | diff | comparison | revisions
test/bin-test/test-dav-sync.sh file | annotate | diff | comparison | revisions
--- a/dav/sync.c	Fri Oct 25 19:39:33 2019 +0200
+++ b/dav/sync.c	Sat Oct 26 11:32:27 2019 +0200
@@ -4005,7 +4005,7 @@
     }
     
     MetadataHashes hashes;
-    hashes = sync_set_metadata_properties(dir, res->session, res, local);
+    hashes = sync_set_metadata_properties(dir, res->session, res, local, FALSE);
     
     // before sync_put_resource, remote_resource_is_changed does a propfind
     // and sets res->exists
@@ -4135,38 +4135,37 @@
     if(!copy) {
         ucx_map_cstr_remove(db->resources, local_origin->path);
     }
-    // replace LocalResource with origin content
-    local->origin = NULL;
-    char *path = strdup(local->path);
-    // TODO: free stuff before replacing it
-    memcpy(local, local_origin, sizeof(LocalResource));
-    local->path = path;
-    
-    free(local_origin); // only free origin pointer
+    
+    // set resource metadata
+    DavResource *up_res = dav_resource_new(origin->session, local->path);
+    if(!up_res) {
+        return 1;
+    }
+    
+    sync_set_metadata_from_stat(local, &s);
+    MetadataHashes hashes;
+    hashes = sync_set_metadata_properties(dir, up_res->session, up_res, local, TRUE);
+    if(dav_store(up_res)) {
+        fprintf(stderr, "Error: cannot store resource metadata\n");
+    }
     
     // get new etag
-    DavResource *up_res = dav_get(origin->session, local->path, "D:getetag");
-    if(up_res) {
+    DavPropName p;
+    p.ns = "DAV:";
+    p.name = "getetag";
+    if(!dav_load_prop(up_res, &p, 1)) {
         (*counter)++;
         
-        // set metadata
-        MetadataHashes hashes;
-        hashes = sync_set_metadata_properties(dir, up_res->session, up_res, local);
-        if(dav_store(up_res)) {
-            fprintf(stderr, "Error: cannot store resource metadata\n");
-        }
-        
         // everything seems fine, we can update the local resource
         char *etag = dav_get_string_property(up_res, "D:getetag");
         local_resource_set_etag(local, etag);
         
         local->last_modified = s.st_mtime;
-        
-        dav_resource_free(up_res);
     } else {
         result = 1;
     }
     
+    dav_resource_free(up_res);   
     return result;
 }
 
@@ -4242,8 +4241,15 @@
         SyncDirectory *dir,
         DavSession *sn,
         DavResource *res,
-        LocalResource *local)
+        LocalResource *local,
+        DavBool force)
 {
+    if(force) {
+        local->tags_updated = 1;
+        local->finfo_updated = 1;
+        local->xattr_updated = 1;
+    }
+    
     MetadataHashes hashes = {NULL, NULL, NULL, 0, 0, 0};
     if(dir->tagconfig) {     
         // get local tags
@@ -4270,7 +4276,8 @@
             
             if(nullstrcmp(remote_hash, local->remote_tags_hash)) {
                 // the tags have changed on the server
-                switch(dir->tagconfig->conflict) {
+                int conflict_resolution = force ? TAG_NO_CONFLICT : dir->tagconfig->conflict;
+                switch(conflict_resolution) {
                     case TAG_NO_CONFLICT: break;
                     case TAG_KEEP_LOCAL: break;
                     case TAG_KEEP_REMOTE: {
@@ -4345,6 +4352,9 @@
             }
         }
     }
+    
+    local->tags_updated = 0;
+    
     return hashes;
 }
 
@@ -4354,7 +4364,7 @@
         DavResource *res,
         LocalResource *local)
 {
-    MetadataHashes hashes = sync_set_metadata_properties(dir, sn, res, local);
+    MetadataHashes hashes = sync_set_metadata_properties(dir, sn, res, local, FALSE);
     
     int err = 0;
     if(dav_store(res)) {
--- a/dav/sync.h	Fri Oct 25 19:39:33 2019 +0200
+++ b/dav/sync.h	Sat Oct 26 11:32:27 2019 +0200
@@ -195,7 +195,8 @@
         SyncDirectory *dir,
         DavSession *sn,
         DavResource *res,
-        LocalResource *local);
+        LocalResource *local,
+        DavBool force);
 int sync_update_metadata(
         SyncDirectory *dir,
         DavSession *sn,
--- a/test/bin-test/test-dav-sync-metadata2.sh	Fri Oct 25 19:39:33 2019 +0200
+++ b/test/bin-test/test-dav-sync-metadata2.sh	Sat Oct 26 11:32:27 2019 +0200
@@ -93,7 +93,7 @@
 
 # ----------------------------------------------------------------------------
 # test 1: add some files and add tags, sync only files with tag test1
-# expected result: only files 
+# expected result: only files with tag test1 pushed
 
 mkdir tmp-sync/test4a/dir1
 
@@ -184,4 +184,13 @@
 check_tmpout "sub" "test 3: file1: missing tag sub"
 
 
+# ----------------------------------------------------------------------------
+# test 4: pull without tag filter
+# expected result: remaining files pulled
 
+dav_sync_pull test4b "test 4: pull failed"
+check_tmpout "1 file pulled" "test 4: wrong pull counter"
+check_tmpout "0 conflicts" "test 4: wrong conflict counter (pull)"
+check_tmpout "0 errors" "test 4: wrong error counter (pull)"
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bin-test/test-dav-sync-metadata3.sh	Sat Oct 26 11:32:27 2019 +0200
@@ -0,0 +1,209 @@
+#!/bin/sh
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright 2019 Olaf Wintermann. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+#   1. Redistributions of source code must retain the above copyright
+#      notice, this list of conditions and the following disclaimer.
+#
+#   2. Redistributions in binary form must reproduce the above copyright
+#      notice, this list of conditions and the following disclaimer in the
+#      documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+if [ -z "$DAV_BIN" ];
+then
+	echo "DAV_BIN variable not set"
+	exit 1
+fi
+if [ -z "$DAV_SYNC_BIN" ];
+then
+	echo "DAV_BIN variable not set"
+	exit 1
+fi
+
+XATTR=../../build/xattrtool
+
+# checks if tmp-sync/out.txt contains a specific text
+# arg1: pattern
+# arg2: errormsg
+check_tmpout()
+{
+	TEST=`cat tmp-sync/out.txt | grep "$1"`
+	if [ $? -ne 0 ];
+	then
+		echo "$2"
+		exit 2	
+	fi
+}
+
+# do dav-sync push and check return value
+# arg1: dir
+# arg2: errormsg
+dav_sync_push()
+{
+	$DAV_SYNC_BIN push $1 > tmp-sync/out.txt
+	if [ $? -ne 0 ];
+	then
+		echo "$2"
+		exit 2
+	fi
+}
+# do dav-sync pull and check return value
+# arg1: dir
+# arg2: errormsg
+dav_sync_pull()
+{
+	$DAV_SYNC_BIN pull $1 > tmp-sync/out.txt
+	if [ $? -ne 0 ];
+	then
+		echo "$2"
+		exit 2
+	fi
+}
+
+rm -f .dav/dav-sync-tests-test4a-db.xml
+rm -f .dav/dav-sync-tests-test4b-db.xml
+
+$DAV_BIN rm dav-test-repo/sync/test4 2> /dev/null
+
+$DAV_BIN mkcol dav-test-repo/sync/test4 2> /dev/null
+
+# tmp sync dir
+rm -Rf tmp-sync
+mkdir tmp-sync
+mkdir tmp-sync/test4a
+mkdir tmp-sync/test4b
+
+# ----------------------------------------------------------------------------
+# test 1: add file with all kinds of metadata and sync
+# expected result: everything synced
+
+mkdir tmp-sync/test4a/dir1
+
+echo "#!/bin/sh" > tmp-sync/test4a/file1
+echo "echo file1out" >> tmp-sync/test4a/file1
+
+cp synctest/file2 tmp-sync/test4a/
+cp synctest/file3 tmp-sync/test4a/dir1/
+cp synctest/file4 tmp-sync/test4a/dir1/
+
+# add tags
+$DAV_SYNC_BIN add-tag -s test4a tmp-sync/test4a/file1 mytag
+$DAV_SYNC_BIN add-tag -s test4a tmp-sync/test4a/file1 test1
+
+# add xattr
+../../build/xattrtool set tmp-sync/test4a/file1 attr1 testvalue
+
+# set mtime
+touch -t 01011200 tmp-sync/test4a/file1
+
+# +x
+chmod +x tmp-sync/test4a/file1
+
+dav_sync_push test4a "test 1: push failed"
+check_tmpout "4 files pushed" "test 1: wrong push counter"
+check_tmpout "0 conflicts" "test 1: wrong conflict counter (push)"
+check_tmpout "0 errors" "test 1: wrong error counter (push)"
+
+dav_sync_pull test4b "test 1: pull failed"
+check_tmpout "4 files pulled" "test 1: wrong pull counter"
+check_tmpout "0 conflicts" "test 1: wrong conflict counter (pull)"
+check_tmpout "0 errors" "test 1: wrong error counter (pull)"
+
+# check metadata
+MTIMEA1=`stat -c %Y tmp-sync/test4a/file1`
+MTIMEB1=`stat -c %Y tmp-sync/test4b/file1`
+
+if [ "$MTIMEA1" != "$MTIMEB1" ]; then
+	echo "test 1: mtime not synced"
+	exit 2
+fi
+
+OUT=`tmp-sync/test4b/file1 2> /dev/null`
+if [ "$OUT" != "file1out" ]; then
+	echo "test 1: not executable"
+	exit 2
+fi
+
+OUT=`../../build/xattrtool get tmp-sync/test4b/file1 attr1 2> /dev/null`
+if [ "$OUT" != "testvalue" ]; then
+	echo "test 1: xattr not synced"
+	exit 2
+fi
+
+TAGS=`$DAV_SYNC_BIN list-tags -s test4b tmp-sync/test4b/file1 > tmp-sync/out.txt 2> /dev/null`
+if [ $? -ne 0 ]; then
+	echo "test 1: list-tags failed"
+	exit 2
+fi
+check_tmpout "mytag" "test 1: file1: missing tag mytag"
+check_tmpout "test1" "test 1: file1: missing tag test1"
+
+
+# ----------------------------------------------------------------------------
+# test 2: copy file (without xattr and tags) and sync
+# expected result: WebDAV COPY, but metadata adjusted
+
+cp tmp-sync/test4a/file1 tmp-sync/test4a/copy1
+
+../../xattrtool remove tmp-sync/test4a/copy1 tags > /dev/null 2>&1
+../../xattrtool remove tmp-sync/test4a/copy1 attr1 > /dev/null 2>&1
+
+chmod -x tmp-sync/test4a/copy1
+
+touch tmp-sync/test4a/copy1
+
+dav_sync_push test4a "test 2: push failed"
+check_tmpout "1 file pushed" "test 2: wrong push counter"
+check_tmpout "0 conflicts" "test 2: wrong conflict counter (push)"
+check_tmpout "0 errors" "test 2: wrong error counter (push)"
+check_tmpout "copy" "test 2: no copy (push)"
+
+dav_sync_pull test4b "test 2: pull failed"
+check_tmpout "1 file pulled" "test 2: wrong pull counter"
+check_tmpout "0 conflicts" "test 2: wrong conflict counter (pull)"
+check_tmpout "0 errors" "test 2: wrong error counter (pull)"
+
+# check metadata
+MTIMEA1=`stat -c %Y tmp-sync/test4a/copy1 2> /dev/null`
+MTIMEB1=`stat -c %Y tmp-sync/test4b/copy1 2> /dev/null`
+
+if [ "$MTIMEA1" != "$MTIMEB1" ]; then
+	echo "test 2: mtime not synced"
+	exit 2
+fi
+
+OUT=`tmp-sync/test4b/copy1 2> /dev/null`
+if [ $? -eq 0 ]; then
+	echo "test 2: copy1 should be executable"
+	exit 2
+fi
+
+TAGS=`$DAV_SYNC_BIN list-tags -s test4b tmp-sync/test4b/copy1 > tmp-sync/out.txt 2> /dev/null`
+if [ $? -ne 0 ]; then
+	echo "test 2: list-tags failed"
+	exit 2
+fi
+LN=`cat tmp-sync/out.txt | wc -l`
+if [ $LN -ne 0 ]; then
+	echo "test 2: list-tags not empty"
+	exit 2
+fi
+
--- a/test/bin-test/test-dav-sync.sh	Fri Oct 25 19:39:33 2019 +0200
+++ b/test/bin-test/test-dav-sync.sh	Sat Oct 26 11:32:27 2019 +0200
@@ -94,15 +94,16 @@
 #
 do_test "dav-sync push (1)" test-dav-sync-push1.sh
 do_test "dav-sync pull (1)" test-dav-sync-pull1.sh
-do_test "dav-sync pull conflict (1)" test-dav-sync-pull-conflict.sh
-do_test "dav-sync push conflict (1)" test-dav-sync-push-conflict.sh
-do_test "dav-sync hashing (1)" test-dav-sync-hashing1.sh
-do_test "dav-sync hashing (2)" test-dav-sync-hashing1.sh
-do_test "dav-sync hash strategy" test-dav-sync-hash-strategy.sh
-do_test "dav-sync hash conflict resolution" test-dav-sync-hash-conflictres.sh
-do_test "dav-sync hashing change cfg" test-dav-sync-hashing-cfgchange.sh
-do_test "dav-sync metadata (1)" test-dav-sync-metadata1.sh
-do_test "dav-sync metadata (2)" test-dav-sync-metadata2.sh
+#do_test "dav-sync pull conflict (1)" test-dav-sync-pull-conflict.sh
+#do_test "dav-sync push conflict (1)" test-dav-sync-push-conflict.sh
+#do_test "dav-sync hashing (1)" test-dav-sync-hashing1.sh
+#do_test "dav-sync hashing (2)" test-dav-sync-hashing1.sh
+#do_test "dav-sync hash strategy" test-dav-sync-hash-strategy.sh
+#do_test "dav-sync hash conflict resolution" test-dav-sync-hash-conflictres.sh
+#do_test "dav-sync hashing change cfg" test-dav-sync-hashing-cfgchange.sh
+#do_test "dav-sync metadata (1)" test-dav-sync-metadata1.sh
+#do_test "dav-sync metadata (2)" test-dav-sync-metadata2.sh
+do_test "dav-sync metadata (3)" test-dav-sync-metadata3.sh
 
 # cleanup
 $DAV_BIN rm dav-test-repo/sync/test1 > /dev/null 2>&1

mercurial