improve copy/move stability and db update

Sun, 07 Apr 2019 13:08:50 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 07 Apr 2019 13:08:50 +0200
changeset 552
e1a12762bf0a
parent 551
99ef8202cd82
child 553
891823d8dd7b

improve copy/move stability and db update

dav/db.c file | annotate | diff | comparison | revisions
dav/db.h file | annotate | diff | comparison | revisions
dav/sync.c file | annotate | diff | comparison | revisions
dav/sync.h file | annotate | diff | comparison | revisions
--- a/dav/db.c	Sun Apr 07 10:44:29 2019 +0200
+++ b/dav/db.c	Sun Apr 07 13:08:50 2019 +0200
@@ -654,6 +654,64 @@
     free(res);
 }
 
+char* nullstrdup(const char *s) {
+    return s ? strdup(s) : NULL;
+}
+
+LocalResource* local_resource_copy(LocalResource *src, const char *new_path) {
+    LocalResource *newres = calloc(1, sizeof(LocalResource));
+    newres->path = strdup(new_path);
+    newres->etag = nullstrdup(src->etag);
+    newres->hash = nullstrdup(src->hash);
+    newres->last_modified = src->last_modified;
+    newres->mode = src->mode;
+    newres->uid = src->uid;
+    newres->gid = src->gid;
+    newres->size = src->size;
+    newres->isdirectory = src->isdirectory;
+    newres->skipped = src->skipped;
+    
+    if(src->xattr) {
+        XAttributes *xattr = calloc(1, sizeof(XAttributes));
+        xattr->hash = nullstrdup(src->xattr->hash);
+        xattr->nattr = src->xattr->nattr;
+        xattr->names = calloc(xattr->nattr, sizeof(char*));
+        xattr->values = calloc(xattr->nattr, sizeof(sstr_t));
+        for(int i=0;i<xattr->nattr;i++) {
+            xattr->names[i] = strdup(src->xattr->names[i]);
+            xattr->values[i] = sstrdup(src->xattr->values[i]);
+        }
+        newres->xattr = xattr;
+    }
+    
+    newres->tags_hash = nullstrdup(src->tags_hash);
+    newres->xattr_hash = nullstrdup(src->xattr_hash);
+    newres->remote_tags_hash = nullstrdup(src->remote_tags_hash);
+    
+    if(src->parts) {
+        newres->numparts = src->numparts;
+        newres->parts = calloc(src->numparts, sizeof(FilePart));
+        for(int i=0;i<newres->numparts;i++) {
+            FilePart s = src->parts[i];
+            FilePart p;
+            p.block = s.block;
+            p.hash = nullstrdup(s.hash);
+            p.etag = nullstrdup(s.etag);
+            newres->parts[i] = p;
+        }
+    }
+    
+    newres->blocksize = src->blocksize;
+    
+    newres->tags_updated = src->tags_updated;
+    newres->finfo_updated = src->finfo_updated;
+    newres->xattr_updated = src->xattr_updated;
+    newres->metadata_updated = src->metadata_updated;
+    
+    return newres;
+    
+}
+
 void filepart_free(FilePart *part) {
     if(part->etag) {
         free(part->etag);
--- a/dav/db.h	Sun Apr 07 10:44:29 2019 +0200
+++ b/dav/db.h	Sun Apr 07 13:08:50 2019 +0200
@@ -82,7 +82,7 @@
     DavBool restore;
     
     DavBool isnew;
-    char *origin;
+    LocalResource *origin;
 };
 
 struct FilePart {
@@ -102,6 +102,8 @@
 
 void local_resource_free(LocalResource *res);
 
+LocalResource* local_resource_copy(LocalResource *src, const char *new_path);
+
 void filepart_free(FilePart *part);
 
 UcxMap* create_hash_index(SyncDatabase *db);
--- a/dav/sync.c	Sun Apr 07 10:44:29 2019 +0200
+++ b/dav/sync.c	Sun Apr 07 13:08:50 2019 +0200
@@ -1595,7 +1595,7 @@
             // check if a file with this hash already exists
             LocalResource *origin = ucx_map_cstr_get(db_hashes, hash);
             if(origin) {
-                local->origin = strdup(origin->path);
+                local->origin = local_resource_copy(origin, origin->path);
                 // the file is a copied/moved file
                 // check if the file is in the resources_map, because then
                 // it still exists
@@ -1732,39 +1732,50 @@
     DavBool copy = TRUE;
     for(UcxList *elm=ls_copy;elm && !sync_shutdown;elm=elm->next) {
         LocalResource *local = elm->data;
-        DavResource *res = dav_resource_new(sn, local->origin);
+        
         int err = 0;
-        if(copy) {
-            printf("copy: %s -> %s\n", local->origin, local->path);
-            err = dav_copy_o(res, local->path, FALSE);
-            
-            if(!elm->next) {
-                // finished copy, begin move
-                elm->next = ls_move;
-                copy = FALSE;
+        DavResource *res = dav_resource_new(sn, local->path);
+        if(dav_exists(res)) {
+            printf("conflict: %s\n", local->path);
+            sync_skipped++;
+        } else {
+            DavResource *origin_res = dav_resource_new(sn, local->origin->path);
+            int origin_changed = remote_resource_is_changed(
+                    sn,
+                    dir,
+                    db,
+                    origin_res,
+                    local->origin);
+            if(origin_changed) {
+                // upload with put
+                printf("put: %s\n", local->path);
+                err = sync_put_resource(dir, res, local, &sync_success);
+            } else {
+                printf("%s: %s -> %s\n", copy ? "copy":"move", local->origin->path, local->path);
+                err = sync_move_remote_resource(
+                        dir,
+                        origin_res,
+                        local,
+                        copy,
+                        &sync_success);
             }
-        } else {
-            printf("move: %s -> %s\n", local->origin, local->path);
-            err = dav_move_o(res, local->path, FALSE);
         }
         
         if(err) {
-            if(sn->error == DAV_PRECONDITION_FAILED) {
-                printf("conflict: %s\n", local->path);
-                local->last_modified = 0;
-                local->skipped = TRUE;
-                sync_skipped++;
-            } else {
-                sync_error++;
-                print_resource_error(sn, res->path);
-                ret = -1;
-                error = 1;
-            }
+            sync_error++;
+            print_resource_error(sn, res->path);
+            ret = -1;
+            error = 1;
         }
         
-        dav_resource_free(res);
         LocalResource *dbres = ucx_map_cstr_remove(db->resources, local->path);
         ucx_map_cstr_put(db->resources, local->path, local);
+        
+        if(copy && !elm->next) {
+            // finished copy, begin move
+            elm->next = ls_move;
+            copy = FALSE;
+        }
     }
     
     // metadata updates
@@ -2228,28 +2239,6 @@
     }
 }
 
-LocalResource* local_resource_copy(LocalResource *res) {
-    LocalResource *newres = calloc(1, sizeof(LocalResource));
-    if(res->name) {
-        newres->name = strdup(res->name);
-    }
-    if(res->path) {
-        newres->path = strdup(res->path);
-    }
-    if(res->etag) {
-        newres->etag = strdup(res->etag);
-    }
-    newres->skipped = res->skipped;
-    newres->size = res->size;
-    newres->last_modified = res->last_modified;
-    newres->isdirectory = res->isdirectory;
-    if(res->tags_hash) {
-       newres->tags_hash = strdup(res->tags_hash); 
-    }
-    newres->tags_updated = res->tags_updated;
-    return newres;
-}
-
 int local_resource_is_changed(
         SyncDirectory *dir,
         SyncDatabase *db,
@@ -3406,6 +3395,78 @@
     return ret;
 }
 
+int sync_move_remote_resource(
+        SyncDirectory *dir,
+        DavResource *origin,
+        LocalResource *local,
+        DavBool copy,
+        int *counter)
+{
+    char *local_path = create_local_path(dir, local->path);
+    
+    SYS_STAT s;
+    if(sys_stat(local_path, &s)) {
+        fprintf(stderr, "Cannot stat file: %s\n", local_path);
+        perror("");
+        free(local_path);
+        return -1;
+    }
+    free(local_path);
+    
+    int result = 0;
+    if(copy) {
+        result = dav_copy_o(origin, local->path, FALSE);
+    } else {
+        result = dav_move_o(origin, local->path, FALSE);
+    }
+    
+    if(result != 0) {
+        return result;
+    }
+    
+    // replace LocalResource with origin content
+    LocalResource *local_origin = local->origin;
+    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
+    
+    // get new etag
+    DavResource *up_res = dav_get(origin->session, origin->path, "D:getetag");
+    if(up_res) {
+        (*counter)++;
+        
+        // everything seems fine, we can update the local resource
+        char *etag = dav_get_string_property(up_res, "D:getetag");
+        if(etag) {
+            if(strlen(etag) > 2 && etag[0] == 'W' && etag[1] == '/') {
+                etag = etag + 2;
+            } 
+        }
+
+        if(local->etag) {
+            free(local->etag);
+        }
+
+        if(etag) {
+            local->etag = strdup(etag);
+        } else {
+            local->etag = NULL;
+        }
+        
+        local->last_modified = s.st_mtime;
+        
+        dav_resource_free(up_res);
+    } else {
+        result = 1;
+    }
+    
+    return result;
+}
+
 int sync_delete_remote_resource(
         SyncDirectory *dir,
         DavSession *sn,
@@ -3440,7 +3501,7 @@
             } 
         }
 
-        if(etag && !strcmp(etag, local_res->etag)) {
+        if(nullstrcmp(etag, local_res->etag)) {
             // local resource metadata == remote resource metadata
             // resource can be deleted
             printf("delete: %s\n", res->path);
--- a/dav/sync.h	Sun Apr 07 10:44:29 2019 +0200
+++ b/dav/sync.h	Sun Apr 07 13:08:50 2019 +0200
@@ -116,7 +116,6 @@
 UcxList* local_scan(SyncDirectory *dir, SyncDatabase *db);
 UcxList* read_changes(SyncDirectory *dir, SyncDatabase *db);
 LocalResource* local_resource_new(SyncDirectory *dir, SyncDatabase *db, char *path, int *isdir);
-LocalResource* local_resource_copy(LocalResource *res);
 int local_resource_is_changed(
         SyncDirectory *dir,
         SyncDatabase *db,
@@ -153,6 +152,12 @@
         LocalResource *local,
         int *counter);
 int sync_mkdir(SyncDirectory *dir, DavResource *res, LocalResource *local);
+int sync_move_remote_resource(
+        SyncDirectory *dir,
+        DavResource *origin,
+        LocalResource *local,
+        DavBool copy,
+        int *counter);
 int sync_delete_remote_resource(SyncDirectory *dir, DavSession *sn, LocalResource *res, int *counter, UcxList **cols);
 MetadataHashes sync_set_metadata_properties(
         SyncDirectory *dir,

mercurial