# HG changeset patch # User Olaf Wintermann # Date 1517594241 -3600 # Node ID 4a6a59f89f9ff2088642a0ffbc66c3ba386bba90 # Parent 5228b912c9256be3e3bd8f2d02583aa7e6716764 adds dav-sync config for autodetecting tag changes diff -r 5228b912c925 -r 4a6a59f89f9f dav/db.c --- 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); } diff -r 5228b912c925 -r 4a6a59f89f9f dav/db.h --- 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 #include +#include #include #include @@ -51,6 +52,8 @@ DavBool isdirectory; DavBool skipped; DavBool tags_updated; + UcxBuffer *cached_tags; + char *tags_hash; }; struct SyncDatabase { diff -r 5228b912c925 -r 4a6a59f89f9f dav/scfg.c --- 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; diff -r 5228b912c925 -r 4a6a59f89f9f dav/scfg.h --- 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(); diff -r 5228b912c925 -r 4a6a59f89f9f dav/sync.c --- 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 #include +#include #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); + } } } diff -r 5228b912c925 -r 4a6a59f89f9f dav/sync.h --- 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( diff -r 5228b912c925 -r 4a6a59f89f9f libidav/crypto.c --- 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 diff -r 5228b912c925 -r 4a6a59f89f9f libidav/crypto.h --- 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