adds xml attribute support and xattr property

Wed, 13 Mar 2019 12:52:24 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Wed, 13 Mar 2019 12:52:24 +0100
changeset 520
da2b0cc44e4f
parent 519
ac5ac55b1b2e
child 521
c5bbae4b3cca

adds xml attribute support and xattr property

dav/finfo.c file | annotate | diff | comparison | revisions
dav/finfo.h file | annotate | diff | comparison | revisions
dav/main.c file | annotate | diff | comparison | revisions
libidav/crypto.c file | annotate | diff | comparison | revisions
libidav/crypto.h file | annotate | diff | comparison | revisions
libidav/webdav.h file | annotate | diff | comparison | revisions
libidav/xml.c file | annotate | diff | comparison | revisions
--- a/dav/finfo.c	Tue Mar 12 09:35:04 2019 +0100
+++ b/dav/finfo.c	Wed Mar 13 12:52:24 2019 +0100
@@ -30,10 +30,15 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/stat.h>
 
 #include <ucx/string.h>
+#include <libidav/crypto.h>
+#include <libidav/utils.h>
+
+#include "libxattr.h"
 
 uint32_t parse_finfo(const char *str) {
     scstr_t s = scstr(str);
@@ -54,6 +59,8 @@
             finfo |= FINFO_OWNER;
         } else if(!sstrcasecmp(f, SC("mode"))) {
             finfo |= FINFO_MODE;
+        } else if(!sstrcasecmp(f, SC("xattr"))) {
+            finfo |= FINFO_XATTR;
         }
         free(f.ptr);
     }
@@ -114,3 +121,79 @@
     
     return 0;
 }
+
+XAttributes* file_get_attributes(const char *path) {
+    ssize_t nelm = 0;
+    char **attributes = xattr_list(path, &nelm);
+    if(nelm <= 0) {
+        return NULL;
+    }
+    
+    XAttributes *xattr = malloc(sizeof(XAttributes));
+    xattr->nattr = 0;
+    xattr->names = calloc(nelm, sizeof(char*));
+    xattr->values = calloc(nelm, sizeof(sstr_t));
+    
+    DAV_SHA_CTX *sha256 = dav_hash_init();
+    
+    size_t nattr = 0;
+    for(int i=0;i<nelm;i++) {
+        ssize_t valuelen = 0;
+        char *value = xattr_get(path, attributes[i], &valuelen);
+        if(valuelen >= 0) {
+            dav_hash_update(sha256, attributes[i], strlen(attributes[i]));
+            dav_hash_update(sha256, value, valuelen);
+            // add name and value
+            xattr->names[nattr] = attributes[i];
+            sstr_t v;
+            v.ptr = value;
+            v.length = valuelen;
+            xattr->values[nattr] = v;
+            nattr++;
+        } else {
+            // discard not readable attributes
+            free(attributes[i]);
+        }
+    }
+    
+    xattr->nattr = nattr;
+    
+    unsigned char hash[DAV_SHA256_DIGEST_LENGTH];
+    dav_hash_final(sha256, hash);
+    xattr->hash = util_hexstr(hash, DAV_SHA256_DIGEST_LENGTH);
+    
+    free(attributes);
+    
+    return xattr;
+}
+
+int resource_set_xattr(DavResource *res, XAttributes *xattr) {
+    if(!xattr || xattr->nattr == 0) {
+        return 0;
+    }
+    
+    DavXmlNode *content = dav_xml_createnode_with_text(DAV_NS, "hash", xattr->hash);
+    DavXmlNode *last = content;
+    
+    for(int i=0;i<xattr->nattr;i++) {
+        DavXmlNode *attr = dav_xml_createnode(DAV_NS, "xattr");
+        dav_xml_add_attr(attr, "name", xattr->names[i]);
+        last->next = attr;
+        last = attr;
+        
+        sstr_t value = xattr->values[i];
+        if(value.length > 0) {
+            char *encval = util_base64encode(value.ptr, value.length);
+            attr->children = dav_xml_createtextnode(encval);
+            free(encval);
+        }
+    }
+    
+    dav_set_property(res, "idav:xattributes", content);
+    
+    return 0;
+}
+
+void xattributes_free(XAttributes *xattr) {
+    
+}
--- a/dav/finfo.h	Tue Mar 12 09:35:04 2019 +0100
+++ b/dav/finfo.h	Wed Mar 13 12:52:24 2019 +0100
@@ -40,12 +40,23 @@
 #define FINFO_DATE  1
 #define FINFO_OWNER 2
 #define FINFO_MODE  4
+#define FINFO_XATTR 8
+    
+typedef struct XAttributes {
+    size_t nattr;
+    char   **names;
+    sstr_t *values;
+    char   *hash;
+} XAttributes;
 
 uint32_t parse_finfo(const char *str);
     
 int resource_set_finfo(const char *path, DavResource *res, uint32_t finfo);
 int resource_set_finfo_s(struct stat *s, DavResource *res, uint32_t finfo);
 
+XAttributes* file_get_attributes(const char *path);
+int resource_set_xattr(DavResource *res, XAttributes *xattr);
+void xattributes_free(XAttributes *xattr);
 
 #ifdef __cplusplus
 }
--- a/dav/main.c	Tue Mar 12 09:35:04 2019 +0100
+++ b/dav/main.c	Wed Mar 13 12:52:24 2019 +0100
@@ -1524,6 +1524,12 @@
     if(resource_set_finfo(fpath, res, finfo)) {
         fprintf(stderr, "Cannot set finfo: %s.\n", strerror(errno));
     }
+    if(finfo & FINFO_XATTR == FINFO_XATTR) {
+        XAttributes *xattr = file_get_attributes(fpath);
+        if(xattr) {
+            resource_set_xattr(res, xattr);
+        }
+    }
     
     dav_set_content(res, in, (dav_read_func)fread, (dav_seek_func)file_seek);
     if(len > 0 && len < 0x7d000000) {
--- a/libidav/crypto.c	Tue Mar 12 09:35:04 2019 +0100
+++ b/libidav/crypto.c	Wed Mar 13 12:52:24 2019 +0100
@@ -359,6 +359,21 @@
     return util_hexstr(hash, DAV_SHA256_DIGEST_LENGTH);
 }
 
+DAV_SHA_CTX* dav_hash_init(void) {
+    DAV_SHA_CTX *ctx = malloc(sizeof(DAV_SHA_CTX));
+    SHA256_Init(ctx);
+    return ctx;
+}
+
+void dav_hash_update(DAV_SHA_CTX *ctx, const char *data, size_t len) {
+    SHA256_Update(ctx, data, len);
+}
+
+void dav_hash_final(DAV_SHA_CTX *ctx, unsigned char *buf) {
+    SHA256_Final(buf, ctx);
+    free(ctx);
+}
+
 DavKey* dav_pw2key(const char *password, const unsigned char *salt, int saltlen, int pwfunc, int enc) {
     if(!password) {
         return NULL;
@@ -779,6 +794,21 @@
     return util_hexstr(hash, DAV_SHA256_DIGEST_LENGTH);
 }
 
+DAV_SHA_CTX* dav_hash_init(void) {
+    DAV_SHA_CTX *ctx = malloc(sizeof(DAV_SHA_CTX));
+    CC_SHA256_Init(ctx);
+    return ctx;
+}
+
+void dav_hash_update(DAV_SHA_CTX *ctx, const char *data, size_t len) {
+    CC_SHA256_Update(ctx, data, len);
+}
+
+void dav_hash_final(DAV_SHA_CTX *ctx, unsigned char *buf) {
+    CC_SHA256_Final(buf, ctx);
+    free(ctx);
+}
+
 DavKey* dav_pw2key(const char *password, const unsigned char *salt, int saltlen, int pwfunc, int enc) {
     if(!password) {
         return NULL;
--- a/libidav/crypto.h	Tue Mar 12 09:35:04 2019 +0100
+++ b/libidav/crypto.h	Wed Mar 13 12:52:24 2019 +0100
@@ -97,6 +97,8 @@
     int            end;
 } AESEncrypter;
 
+typedef struct DavHashContext DavHashContext;
+
 int dav_rand_bytes(unsigned char *buf, size_t len);
 
 AESDecrypter* aes_decrypter_new(DavKey *key, void *stream, dav_write_func write_func);
@@ -116,6 +118,10 @@
 
 char* dav_create_hash(const char *data, size_t len);
 
+DAV_SHA_CTX* dav_hash_init(void);
+void dav_hash_update(DAV_SHA_CTX *ctx, const char *data, size_t len);
+void dav_hash_final(DAV_SHA_CTX *ctx, unsigned char *buf);
+
 DavKey* dav_pw2key(const char *password, const unsigned char *salt, int saltlen, int pwfunc, int enc);
 
 UcxBuffer* aes_encrypt_buffer(UcxBuffer *buf, DavKey *key);
--- a/libidav/webdav.h	Tue Mar 12 09:35:04 2019 +0100
+++ b/libidav/webdav.h	Wed Mar 13 12:52:24 2019 +0100
@@ -59,6 +59,7 @@
 typedef struct DavPropName   DavPropName;
 typedef struct DavKey        DavKey;
 typedef struct DavXmlNode    DavXmlNode;
+typedef struct DavXmlAttr    DavXmlAttr;
 
 typedef size_t(*dav_read_func)(void*, size_t, size_t, void*);
 typedef size_t(*dav_write_func)(const void*, size_t, size_t, void*);
@@ -206,12 +207,18 @@
     DavXmlNode     *children;
     DavXmlNode     *parent;
     
-    // TODO: attributes
+    DavXmlAttr     *attributes;
     
     char           *content;
     size_t         contentlength;
 };
 
+struct DavXmlAttr {
+    char *name;
+    char *value;
+    DavXmlAttr *next;
+};
+
 DavContext* dav_context_new();
 void dav_context_destroy(DavContext *ctx);
 
@@ -333,6 +340,7 @@
 DavXmlNode* dav_xml_createnode_with_text(const char *ns, const char *name, const char *text);
 DavXmlNode* dav_xml_createtextnode(const char *text);
 void dav_xml_add_child(DavXmlNode *node, DavXmlNode *child);
+void dav_xml_add_attr(DavXmlNode *node, const char *name, const char *value);
 
 DavXmlNode* dav_parse_xml(DavSession *sn, const char *str, size_t len);
 
--- a/libidav/xml.c	Tue Mar 12 09:35:04 2019 +0100
+++ b/libidav/xml.c	Wed Mar 13 12:52:24 2019 +0100
@@ -94,7 +94,25 @@
                     newxn->namespace = dav_session_strdup(sn, (char*)n->ns->href);
                 }
                 
-                // TODO: copy attributes
+                xmlAttr *attr = n->properties;
+                DavXmlAttr *newattr = NULL;
+                DavXmlAttr *newattr_last = NULL;
+                while(attr) {
+                    DavXmlAttr *na = ucx_mempool_calloc(mp, 1, sizeof(DavXmlAttr));
+                    na->name = dav_session_strdup(sn, (char*)attr->name);
+                    if(attr->children && attr->children->type == XML_TEXT_NODE) {
+                        na->value = dav_session_strdup(sn, (char*)attr->children->content);
+                    }
+                    if(!newattr) {
+                        newattr = na;
+                    } else {
+                        newattr_last->next = na;
+                    }
+                    newattr_last = na;
+                    
+                    attr = attr->next;
+                }
+                newxn->attributes = newattr;
                 
                 if(n->children) {
                     ConvXmlElm *convc = malloc(sizeof(ConvXmlElm));
@@ -120,7 +138,13 @@
 
 void dav_print_xml(DavXmlNode *node) {
     if(node->type == DAV_XML_ELEMENT) {
-        printf("<%s>", node->name);
+        printf("<%s", node->name);
+        DavXmlAttr *attr = node->attributes;
+        while(attr) {
+            printf(" %s=\"%s\"", attr->name, attr->value);
+            attr = attr->next;
+        }
+        putchar('>');
         
         DavXmlNode *child = node->children;
         if(child) {
@@ -140,7 +164,7 @@
 void dav_print_node(void *stream, write_func writef, UcxMap *nsmap, DavXmlNode *node) {
     while(node) {
         if(node->type == DAV_XML_ELEMENT) {
-            char *tagend = node->children ? ">" : " />";
+            char *tagend = node->children ? ">" : " />";          
             char *prefix = NULL;
             if(node->namespace) {
                 prefix = ucx_map_cstr_get(nsmap, node->namespace);
@@ -158,12 +182,19 @@
                             node->namespace,
                             tagend);
                 } else {
-                    ucx_fprintf(stream, writef, "<%s:%s%s", prefix, node->name, tagend);
+                    ucx_fprintf(stream, writef, "<%s:%s", prefix, node->name);
                 }
             } else {
-                ucx_fprintf(stream, writef, "<%s%s", node->name, tagend);
+                ucx_fprintf(stream, writef, "<%s", node->name);
             }
             
+            DavXmlAttr *attr = node->attributes;
+            while(attr) {
+                ucx_fprintf(stream, writef, " %s=\"%s\"", attr->name, attr->value);
+                attr = attr->next;
+            }
+            writef(tagend, 1, strlen(tagend), stream); // end xml tag
+            
             if(node->children) {
                 dav_print_node(stream, writef, nsmap, node->children);
                 if(prefix) {
@@ -296,6 +327,24 @@
     }
 }
 
+void dav_xml_add_attr(DavXmlNode *node, const char *name, const char *value) {
+    DavXmlAttr *attr = calloc(1, sizeof(DavXmlAttr));
+    attr->name = strdup(name);
+    attr->value = strdup(value);
+    
+    if(node->attributes) {
+        DavXmlAttr *last;
+        DavXmlAttr *end = node->attributes;
+        while(end) {
+            last = end;
+            end = end->next;
+        }
+        last->next = attr;
+    } else {
+        node->attributes = attr;
+    }
+}
+
 DavXmlNode* dav_parse_xml(DavSession *sn, const char *str, size_t len) {
     xmlDoc *doc = xmlReadMemory(str, len, NULL, NULL, 0);
     if(!doc) {

mercurial