adds dav-sync config for autodetecting tag changes

Fri, 02 Feb 2018 18:57:21 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 02 Feb 2018 18:57:21 +0100
changeset 367
4a6a59f89f9f
parent 366
5228b912c925
child 368
11797f33bc24

adds dav-sync config for autodetecting tag changes

dav/db.c file | annotate | diff | comparison | revisions
dav/db.h file | annotate | diff | comparison | revisions
dav/scfg.c file | annotate | diff | comparison | revisions
dav/scfg.h file | annotate | diff | comparison | revisions
dav/sync.c file | annotate | diff | comparison | revisions
dav/sync.h file | annotate | diff | comparison | revisions
libidav/crypto.c file | annotate | diff | comparison | revisions
libidav/crypto.h file | annotate | diff | comparison | revisions
--- a/dav/db.c	Fri Feb 02 16:46:04 2018 +0100
+++ b/dav/db.c	Fri Feb 02 18:57:21 2018 +0100
@@ -122,6 +122,8 @@
                 field = 2;
             } else if(xstreq(name, "size")) {
                 field = 3;
+            } else if(xstreq(name, "tags-hash")) {
+                field = 4;
             } else if(xstreq(name, "skipped")) {
                 res->skipped = TRUE;
             } else if(xstreq(name, "tags-updated")) {
@@ -163,6 +165,10 @@
                     }
                     break;
                 }
+                case 4: {
+                    res->tags_hash = strdup((char*)value);
+                    break;
+                }
             }
         } else if(XML_READER_TYPE_END_ELEMENT) {
             if(xstreq(name, "resource")) {
@@ -286,6 +292,18 @@
             return -1;
         }
         
+        if(res->tags_hash) {
+            r = xmlTextWriterWriteElement(
+                    writer,
+                    BAD_CAST "tags-hash",
+                    BAD_CAST res->tags_hash);
+            if(r < 0) {
+                fprintf(stderr, "Cannot write tags-hash: %s\n", res->etag);
+                xmlFreeTextWriter(writer);
+                return -1;
+            }
+        }
+        
         if(res->skipped) {
             r = xmlTextWriterStartElement(writer, BAD_CAST "skipped");
             r += xmlTextWriterEndElement(writer);
@@ -374,5 +392,11 @@
     if(res->etag) {
         free(res->etag);
     }
+    if(res->cached_tags) {
+        ucx_buffer_free(res->cached_tags);
+    }
+    if(res->tags_hash) {
+        free(res->tags_hash);
+    }
     free(res);
 }
--- a/dav/db.h	Fri Feb 02 16:46:04 2018 +0100
+++ b/dav/db.h	Fri Feb 02 18:57:21 2018 +0100
@@ -31,6 +31,7 @@
 
 #include <libidav/webdav.h>
 #include <ucx/map.h>
+#include <ucx/buffer.h>
 #include <time.h>
 
 #include <libxml/xmlreader.h>
@@ -51,6 +52,8 @@
     DavBool isdirectory;
     DavBool skipped;
     DavBool tags_updated;
+    UcxBuffer *cached_tags;
+    char *tags_hash;
 };
 
 struct SyncDatabase {
--- a/dav/scfg.c	Fri Feb 02 16:46:04 2018 +0100
+++ b/dav/scfg.c	Fri Feb 02 18:57:21 2018 +0100
@@ -155,11 +155,12 @@
     conf.store = TAG_STORE_XATTR;
     conf.local_format = TAG_FORMAT_TEXT;
     conf.server_format = TAG_FORMAT_XML;
+    conf.scan = false;
     xmlNode *c = node->children;
     
     // TODO: error handling
     while(c) {
-        if(node->type == XML_ELEMENT_NODE) {
+        if(c->type == XML_ELEMENT_NODE) {
             char *value = util_xml_get_text(c);
             if(xstreq(c->name, "local-store")) {  
                 if(!value) {
@@ -183,6 +184,11 @@
                     }
                     attr = attr->next;
                 }
+            } else if(xstreq(c->name, "scan")) {
+                if(!value) {
+                    return NULL;
+                }
+                conf.scan = util_getboolean(value);
             }
         }
         c = c->next;
--- a/dav/scfg.h	Fri Feb 02 16:46:04 2018 +0100
+++ b/dav/scfg.h	Fri Feb 02 18:57:21 2018 +0100
@@ -82,6 +82,7 @@
     TagStore store;
     TagFormat local_format;
     TagFormat server_format;
+    bool scan;
 };
 
 int load_sync_config();
--- a/dav/sync.c	Fri Feb 02 16:46:04 2018 +0100
+++ b/dav/sync.c	Fri Feb 02 18:57:21 2018 +0100
@@ -42,6 +42,7 @@
 
 #include <libidav/webdav.h>
 #include <libidav/utils.h>
+#include <libidav/crypto.h>
 
 #include "config.h"
 #include "scfg.h"
@@ -1247,6 +1248,21 @@
             res->etag = strdup(db_res->etag);
         }
         
+        if(dir->tagconfig && dir->tagconfig->scan && !res->tags_updated) {
+            UcxBuffer *tags = sync_get_file_tag_data(dir, res);
+            if(tags) {
+                if(db_res->tags_hash) {
+                    char *hash = dav_create_hash(tags->space, tags->size);
+                    if(strcmp(hash, db_res->tags_hash)) {
+                        res->tags_updated = 1;
+                    }
+                    free(hash);
+                } else {
+                    res->tags_updated = 1;
+                }
+            }
+        }
+        
         if(db_res->last_modified == res->last_modified && db_res->size == res->size) {
             return 0;
         }
@@ -1350,6 +1366,28 @@
     return ret;
 }
 
+UcxBuffer* sync_get_file_tag_data(SyncDirectory *dir, LocalResource *res) {
+    if(!dir->tagconfig) {
+        return NULL;
+    }
+    UcxBuffer *buf = NULL;
+    if(dir->tagconfig->store == TAG_STORE_XATTR) {
+        ssize_t tag_length = 0;
+        char *local_path = util_concat_path(dir->path, res->path);
+        char* tag_data = xattr_get(
+                local_path,
+                dir->tagconfig->local_format == TAG_FORMAT_MACOS ? MACOS_TAG_XATTR : "tags",
+                &tag_length);
+        free(local_path);
+        
+        if(tag_length > 0) {
+            buf = ucx_buffer_new(tag_data, (size_t)tag_length, UCX_BUFFER_AUTOFREE);
+            buf->size = (size_t)tag_length;
+        }
+    }
+    return buf;
+}
+
 UcxList* sync_get_file_tags(SyncDirectory *dir, LocalResource *res) {
     UcxList *tags = NULL;
     
@@ -1357,27 +1395,32 @@
         return NULL;
     }
     if(dir->tagconfig->store == TAG_STORE_XATTR) {
-        ssize_t tag_length = 0;
-        char *local_path = util_concat_path(dir->path, res->path);
-        char* tag_data = xattr_get(local_path, "tags", &tag_length);
-        free(local_path);
+        UcxBuffer *tag_buf = res->cached_tags ?
+                res->cached_tags :
+                sync_get_file_tag_data(dir, res);
         
-        if(tag_length > 0) {
+        if(tag_buf) {
+            res->tags_hash = dav_create_hash(tag_buf->space, tag_buf->size);
+            
             switch(dir->tagconfig->local_format) {
                 default: break;
                 case TAG_FORMAT_TEXT: {
-                    tags = parse_text_taglist(tag_data, tag_length);
+                    tags = parse_text_taglist(tag_buf->space, tag_buf->size);
                     break;
                 }
                 case TAG_FORMAT_CSV: {
-                    tags = parse_csv_taglist(tag_data, tag_length);
+                    tags = parse_csv_taglist(tag_buf->space, tag_buf->size);
                     break;
                 }
                 case TAG_FORMAT_MACOS: {
-                    tags = parse_macos_taglist(tag_data, tag_length);
+                    tags = parse_macos_taglist(tag_buf->space, tag_buf->size);
                     break;
                 }
             }
+            if(!res->cached_tags) {
+                // we created the buffer therefore we destroy it
+                ucx_buffer_free(tag_buf);
+            }
         }
     }
     
--- a/dav/sync.h	Fri Feb 02 16:46:04 2018 +0100
+++ b/dav/sync.h	Fri Feb 02 18:57:21 2018 +0100
@@ -50,6 +50,8 @@
 #endif
 
 #define STDIN_BUF_SIZE 2048
+    
+#define MACOS_TAG_XATTR "com.apple.metadata:_kMDItemUserTags"
 
 void print_usage(char *cmd);
 
@@ -83,6 +85,7 @@
 
 int sync_set_status(DavResource *res, char *status);
 int sync_remove_status(DavResource *res);
+UcxBuffer* sync_get_file_tag_data(SyncDirectory *dir, LocalResource *res);
 UcxList* sync_get_file_tags(SyncDirectory *dir, LocalResource *res);
 int sync_store_tags(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res);
 int sync_put_resource(
--- a/libidav/crypto.c	Fri Feb 02 16:46:04 2018 +0100
+++ b/libidav/crypto.c	Fri Feb 02 18:57:21 2018 +0100
@@ -332,6 +332,12 @@
     SHA256_Final((unsigned char*)buf, sha256);
 }
 
+char* dav_create_hash(const char *data, size_t len) {
+    unsigned char hash[DAV_SHA256_DIGEST_LENGTH];
+    SHA256((const unsigned char*)data, len, hash);
+    return util_hexstr(hash, DAV_SHA256_DIGEST_LENGTH);
+}
+
 #endif
 
 
@@ -673,4 +679,10 @@
     CC_SHA256_Final(buf, sha256);
 }
 
+char* dav_create_hash(const char *data, size_t len) {
+    unsigned char hash[DAV_SHA256_DIGEST_LENGTH];
+    CC_SHA256((const unsigned char*)data, len, hash);
+    return util_hexstr(hash, DAV_SHA256_DIGEST_LENGTH);
+}
+
 #endif
--- a/libidav/crypto.h	Fri Feb 02 16:46:04 2018 +0100
+++ b/libidav/crypto.h	Fri Feb 02 18:57:21 2018 +0100
@@ -107,6 +107,8 @@
 
 void dav_get_hash(DAV_SHA_CTX *sha256, unsigned char *buf);
 
+char* dav_create_hash(const char *data, size_t len);
+
 #ifdef	__cplusplus
 }
 #endif

mercurial