dav/sync.c

changeset 526
e3c0440bd599
parent 525
26a1d5b9d9d2
child 527
d0e37224eba1
--- a/dav/sync.c	Sun Mar 17 15:00:48 2019 +0100
+++ b/dav/sync.c	Sun Mar 17 18:11:31 2019 +0100
@@ -33,6 +33,7 @@
 #include <unistd.h>
 #include <signal.h>
 #include <time.h>
+#include <utime.h>
 #include <libxml/xmlerror.h>
 #include <sys/types.h>
 #include <ucx/string.h>
@@ -499,7 +500,7 @@
     }
     
     int ret = 0;
-    DavResource *ls = dav_query(sn, "select D:getetag,idav:status,idav:tags from / with depth = infinity");
+    DavResource *ls = dav_query(sn, "select D:getetag,idav:status,idav:tags,idav:finfo,idav:xattributes from / with depth = infinity");
     if(!ls) {
         print_resource_error(sn, "/");
         if(locked) {
@@ -549,7 +550,7 @@
     UcxList *res_broken = NULL;
     UcxList *lres_removed = NULL; // list of LocalResource*
     
-    UcxMap *svrres = ucx_map_new(db->resources->count);
+    //UcxMap *svrres = ucx_map_new(db->resources->count);
     UcxMap *dbres = ucx_map_clone(db->resources, NULL, NULL);
     
     UcxList *statls = NULL;
@@ -695,9 +696,18 @@
         
         LocalResource *local = ucx_map_cstr_get(db->resources, res->path);
         if(local) {
+            printf("update: %s\n", res->path);
             char *local_path = util_concat_path(dir->path, res->path);
-            if(sync_store_tags(dir, local_path, local, res)) {
-                fprintf(stderr, "Tag update failed: %s\n", res->path);
+            if(sync_store_metadata(dir, local_path, local, res)) {
+                fprintf(stderr, "Metadata update failed: %s\n", res->path);
+                sync_error++;
+            } else {
+                struct stat s;
+                if(stat(local_path, &s)) {
+                    fprintf(stderr, "Cannot stat file after update: %s\n", strerror(errno));
+                }
+                sync_set_metadata_from_stat(local, &s);
+                sync_success++;
             }
             free(local_path);
         } else {
@@ -819,9 +829,6 @@
             }
             if(!strcmp(e.ptr, local->etag)) {
                 // resource is already up-to-date on the client
-                
-                // TODO: detect metadata update
-                //sync_store_tags(dir, local_path, local, res);
                 nochange = TRUE;
             }
         }
@@ -838,18 +845,64 @@
         ret = REMOTE_CHANGE_NEW;
     }
     
-    if(ret == REMOTE_NO_CHANGE) {
+    while(ret == REMOTE_NO_CHANGE && local) {
         // check if tags have changed
         if(dir->tagconfig) {
+            DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_NS, "tags");
+            UcxList *remote_tags = NULL;
+            if(tagsprop) {
+                remote_tags = parse_dav_xml_taglist(tagsprop);
+            }
+            char *remote_hash = create_tags_hash(remote_tags);
+            if(nullstrcmp(remote_hash, local->remote_tags_hash)) {
+                ret = REMOTE_CHANGE_METADATA;
+            }
+            if(remote_hash) {
+                free(remote_hash);
+            }
+            free_taglist(remote_tags);
             
+            if(ret == REMOTE_CHANGE_METADATA) {
+                break;
+            }
         }
         
+        // check if extended attributes have changed
+        if(dir->metadata & FINFO_XATTR == FINFO_XATTR) {
+            DavXmlNode *xattr = dav_get_property_ns(res, DAV_NS, "xattributes");
+            char *xattr_hash = get_xattr_hash(xattr);
+            if(nullstrcmp(xattr_hash, local->xattr_hash)) {
+                ret = REMOTE_CHANGE_METADATA;
+                break;
+            }
+        } 
+        
+        // check if finfo has changed
+        DavXmlNode *finfo = dav_get_property_ns(res, DAV_NS, "finfo");
+        if(dir->metadata & FINFO_MODE == FINFO_MODE) {
+            FileInfo f;
+            finfo_get_values(finfo, &f);
+            if(f.mode_set && f.mode != local->mode) {
+                ret = REMOTE_CHANGE_METADATA;
+                break;
+            }
+        }
+        
+        break;
     }
     
     free(local_path);
     return ret;
 }
 
+void sync_set_metadata_from_stat(LocalResource *local, struct stat *s) {
+    local->last_modified = s->st_mtime;
+    local->mode = s->st_mode & 07777;
+    local->uid = s->st_uid;
+    local->gid = s->st_gid;
+    local->size = s->st_size;
+}
+
 int sync_get_resource(
         CmdArgs *a,
         SyncDirectory *dir,
@@ -887,6 +940,10 @@
 
     if(ret == 0) {
         (*counter)++;
+        
+        if(sync_store_metadata(dir, tmp_path, local, res)) {
+            fprintf(stderr, "Cannot store metadata: %s\n", res->path);
+        }
 
         if(dir->trash && dir->backuppull) {
             move_to_trash(dir, local_path);
@@ -918,13 +975,11 @@
         if(local->etag) {
             free(local->etag);
         }
+        
         // set metadata from stat
         local->etag = strdup(etag);
-        local->last_modified = s.st_mtime;
-        local->size = s.st_size;
+        sync_set_metadata_from_stat(local, &s);
         local->skipped = FALSE;
-        
-        sync_store_tags(dir, tmp_path, local, res);
     } else {
         if(sys_unlink(tmp_path)) {
             fprintf(stderr, "Cannot remove tmp file: %s\n", tmp_path);
@@ -1849,6 +1904,11 @@
         if(db_res->last_modified == res->last_modified && db_res->size == res->size) {
             return 0;
         }
+    } else {
+        res->tags_updated = 1;
+        res->finfo_updated = 1;
+        res->xattr_updated = 1;
+        res->metadata_updated = 1;
     }
     return 1;
 }
@@ -1954,6 +2014,66 @@
     return equal;
 }
 
+int sync_store_metadata(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res) {
+    int ret = 0;
+    
+    DavXmlNode *fileinfo = dav_get_property_ns(res, DAV_NS, "finfo");
+    if(fileinfo) {
+        FileInfo f;
+        finfo_get_values(fileinfo, &f);
+        if(dir->metadata & FINFO_DATE == FINFO_DATE && f.date_set) {
+            // set mtime
+            struct utimbuf t;
+            t.actime = f.last_modified;
+            t.modtime = f.last_modified;
+            if(utime(path, &t)) {
+                fprintf(stderr, "utime failed for file: %s : %s\n", path, strerror(errno));
+                ret = 1;
+            }
+        }
+        if(dir->metadata & FINFO_MODE == FINFO_MODE && f.mode_set) {
+            // set mode
+            if(chmod(path, f.mode)) {
+                fprintf(stderr, "chmod failed for file: %s : %s\n", path, strerror(errno));
+                ret = 1;
+            }
+        }
+    }
+    
+    DavXmlNode *xattr_prop = dav_get_property_ns(res, DAV_NS, "xattributes");
+    if(xattr_prop) {
+        XAttributes *xattr = xml_get_attributes(xattr_prop);
+        if(xattr) {
+            if(!sync_store_xattr(dir, path, xattr)) {
+                if(local->xattr_hash) {
+                    free(local->xattr_hash);
+                }
+                local->xattr_hash = xattr->hash;
+            }
+        }
+    }
+    
+    if(sync_store_tags(dir, path, local, res)) {
+        ret = 1;
+    }
+    
+    return ret;
+}
+
+int sync_store_xattr(SyncDirectory *dir, const char *path, XAttributes *xattr) {
+    for(int i=0;i<xattr->nattr;i++) {
+        sstr_t value = xattr->values[i];
+        if(xattr_set(path, xattr->names[i], value.ptr, value.length)) {
+            fprintf(
+                    stderr,
+                    "Cannot store xattr '%s' for file: %s\n",
+                    xattr->names[i],
+                    path);
+        }
+    }
+    return 0;
+}
+
 int sync_store_tags(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res) {
     if(!dir->tagconfig) {
         return 0;
@@ -1973,7 +2093,10 @@
     UcxList *local_tags = sync_get_file_tags(dir, local, &tags_changed, NULL);
     if(tags_changed) {
         switch(dir->tagconfig->conflict) {
-            case TAG_NO_CONFLICT:
+            case TAG_NO_CONFLICT: {
+                store_tags = TRUE;
+                break;
+            }
             case TAG_KEEP_LOCAL: {
                 store_tags = FALSE;
                 break;
@@ -2036,7 +2159,7 @@
                 int update = 1;
                 if(local) {
                     if(!local->tags_hash || strcmp(data_hash, local->tags_hash)) {
-                        printf("update: %s\n", local->path);
+                        //printf("update: %s\n", local->path);
                     } else {
                         update = 0;
                     }
@@ -2058,7 +2181,7 @@
             }
         } else {
             if(local) {
-                printf("update: %s\n", local->path);
+                //printf("update: %s\n", local->path);
             }
             ret = xattr_remove(path, dir->tagconfig->xattr_name);
         }

mercurial