dav/sync.c

changeset 686
ab159748055c
parent 685
487645580b5e
child 687
9922a349a61a
--- a/dav/sync.c	Sat Nov 23 17:49:18 2019 +0100
+++ b/dav/sync.c	Sun Nov 24 12:40:28 2019 +0100
@@ -969,6 +969,8 @@
         SyncDirectory *dir,
         SyncDatabase *db)
 {
+    DavBool update_db = FALSE;
+    
     char *etag = dav_get_string_property(res, "D:getetag");
     if(!etag) {
         fprintf(stderr, "Error: resource %s has no etag\n", res->path);
@@ -1017,6 +1019,19 @@
         if(SYNC_SYMLINK(dir) && nullstrcmp(link, local->link_target)) {
             ret = REMOTE_CHANGE_LINK;
             nochange = TRUE;
+            
+            if(local->link_target) {
+                LocalResource *local2 = local_resource_new(dir, db, local->path);
+                if(type == REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED && nullstrcmp(local->link_target, local2->link_target)) {
+                    ret = REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED;
+                }            
+                local_resource_free(local2);
+
+                if(!nullstrcmp(link, local->link_target)) {
+                    ret = REMOTE_NO_CHANGE;
+                    update_db = TRUE;
+                }
+            } 
         } else if(issplit && local->hash && hash) {
             if(!strcmp(local->hash, hash)) {
                 // resource is already up-to-date on the client
@@ -1040,11 +1055,26 @@
             ret = type;
         }
     } else if(link) {
+        // new file is a link
+        ret = REMOTE_CHANGE_LINK;
+        
         if(exists && type == REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED) {
-            ret = REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED;
-        } else {
-            ret = REMOTE_CHANGE_LINK;
-        }
+            // a file with the same name already exists
+            // if it is a link, compare the targets
+            LocalResource *local2 = local_resource_new(dir, db, res->path);
+            if(local2) {
+                if(local2->link_target) {
+                    if(strcmp(link, local2->link_target)) {
+                        ret = REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED;
+                    }
+                } else {
+                    ret = REMOTE_CHANGE_CONFLICT_LOCAL_MODIFIED;
+                }
+                
+                local_resource_free(local2);
+            }
+        }
+        
     } else if(exists) {
         ret = type;
     } else {
@@ -1053,7 +1083,6 @@
      
     // 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
-    DavBool update_db = FALSE;
     char *update_hash = NULL;
     if (!iscollection &&
         !link &&
@@ -1155,6 +1184,10 @@
         if(!local->hash) {
             local->hash = update_hash;
         } // else: hash already updated
+        if(link) {
+            nullfree(local->link_target);
+            local->link_target = link;
+        }
     }
         
     free(local_path);
@@ -2210,6 +2243,7 @@
             sync_error++;
         } else {
             DavBool equal = FALSE;
+            DavBool res_conflict = FALSE;
             int changed = remote_resource_is_changed(sn, dir, db, res, local_res, &equal);
             if(equal) {
                 char *etag = dav_get_string_property(res, "D:getetag");
@@ -2231,6 +2265,14 @@
                 local_res->hash = NULL;
                 local_res->skipped = TRUE;
                 sync_conflict++;
+                
+                if(local_res->link_target) {
+                    free(local_res->link_target);
+                    local_res->link_target = local_res->link_target_db;
+                    local_res->link_target_db = NULL;
+                }
+                
+                res_conflict = TRUE;
             } else {
                 if(local_res->link_target) {
                     printf(
@@ -2252,7 +2294,11 @@
             
             if(!err) {
                 LocalResource *dbres = ucx_map_cstr_remove(db->resources, local_res->path);
-                ucx_map_cstr_put(db->resources, local_res->path, local_res);
+                // in case of a conflict, don't store the resource
+                // in the db, if it is new
+                if(!res_conflict || dbres) {
+                    ucx_map_cstr_put(db->resources, local_res->path, local_res);
+                }
             }
         }
         
@@ -2847,6 +2893,9 @@
         if(db_res->hash) {
             res->prev_hash = strdup(db_res->hash);
         }
+        if(db_res->link_target) {
+            res->link_target_db = db_res->link_target;
+        }
         
         // if the resource is splitted, copy the part info to the new
         // LocalResource obj, because we need it later
@@ -3005,11 +3054,21 @@
         return 1;
     }
     
+    char *link = dav_get_string_property_ns(remote, DAV_PROPS_NS, "link");
+    
     int ret = 0;
     if(err == 0) {
         char *etag = dav_get_string_property(remote, "D:getetag");
         char *hash = sync_get_content_hash(remote);
         
+        if(res->link_target_db || link) {
+            ret = nullstrcmp(res->link_target_db, link);
+            if(ret && equal) {
+                *equal = !nullstrcmp(res->link_target, link);
+            }
+            return ret;
+        }
+        
         if(hash && res->hash && equal) {
             // if requested, check if the local and remote res are equal
             if(!strcmp(hash, res->hash)) {

mercurial