UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2019 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "finfo.h" 30 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <errno.h> 35 #include <sys/stat.h> 36 #include <limits.h> 37 38 #include <cx/string.h> 39 #include <cx/list.h> 40 #include <cx/array_list.h> 41 #include <libidav/crypto.h> 42 #include <libidav/utils.h> 43 44 #ifndef _WIN32 45 #include <unistd.h> 46 #endif 47 48 #include "libxattr.h" 49 50 uint32_t parse_finfo_settings(const char *str, char **error) { 51 cxstring s = cx_str(str); 52 53 if(!cx_strcmp(s, CX_STR("*")) || !cx_strcmp(s, CX_STR("a")) || !cx_strcmp(s, CX_STR("all"))) { 54 return FINFO_MTIME|FINFO_OWNER|FINFO_MODE|FINFO_XATTR; 55 } 56 57 CxStrtokCtx fs = cx_strtok(s, CX_STR(","), INT_MAX); 58 cxstring f; 59 uint32_t finfo = 0; 60 char *err = NULL; 61 while(cx_strtok_next(&fs, &f)) { 62 if(!cx_strcasecmp(f, CX_STR("mtime"))) { 63 finfo |= FINFO_MTIME; 64 } else if(!cx_strcasecmp(f, CX_STR("owner"))) { 65 finfo |= FINFO_OWNER; 66 } else if(!cx_strcasecmp(f, CX_STR("mode"))) { 67 finfo |= FINFO_MODE; 68 } else if(!cx_strcasecmp(f, CX_STR("xattr"))) { 69 finfo |= FINFO_XATTR; 70 } else if(error && !err) { 71 err = cx_strdup(f).ptr; 72 continue; 73 } 74 } 75 76 return err ? 0 : finfo; 77 } 78 79 int resource_set_finfo(const char *path, DavResource *res, uint32_t finfo) { 80 if(!path || finfo == 0) { 81 return 0; 82 } 83 84 struct stat s; 85 if(stat(path, &s)) { 86 fprintf(stderr, "failed to stat: %s\n", path); 87 return 1; 88 } 89 return resource_set_finfo_s(&s, res, finfo); 90 } 91 92 int resource_set_finfo_s(struct stat *s, DavResource *res, uint32_t finfo) { 93 if(finfo == 0) { 94 return 0; 95 } 96 97 DavXmlNode *content = NULL; 98 DavXmlNode *last = NULL; 99 100 if((finfo & FINFO_MTIME) == FINFO_MTIME) { 101 char str[32]; 102 struct tm *date = gmtime(&s->st_mtime); 103 strftime(str, 32, "%a, %d %b %Y %H:%M:%S GMT", date); 104 DavXmlNode *mtime = dav_text_element(res->session, DAV_PROPS_NS, "mtime", str); 105 content = mtime; 106 last = mtime; 107 } 108 #ifndef _WIN32 109 if((finfo & FINFO_OWNER) == FINFO_OWNER) { 110 // TODO 111 } 112 if((finfo & FINFO_MODE) == FINFO_MODE) { 113 mode_t mode = s->st_mode & 07777; 114 char str[32]; 115 snprintf(str, 32, "%o", (int)mode); 116 DavXmlNode *xmode = dav_text_element(res->session, DAV_PROPS_NS, "mode", str); 117 if(last) { 118 last->next = xmode; 119 } else { 120 content = xmode; 121 } 122 last = xmode; 123 } 124 #endif 125 126 127 dav_set_property_ns(res, DAV_PROPS_NS, "finfo", content);; 128 129 return 0; 130 } 131 132 133 static void* array_realloc(void *array, 134 size_t capacity, 135 size_t elem_size, 136 struct cx_array_reallocator_s *alloc) 137 { 138 return realloc(array, capacity * elem_size); 139 } 140 141 XAttributes* xml_get_attributes(DavXmlNode *xml) { 142 XAttributes *attributes = calloc(1, sizeof(XAttributes)); 143 size_t x_names_size = 0; 144 size_t x_names_alloc = 8; 145 size_t x_values_size = 0; 146 size_t x_values_alloc = 8; 147 attributes->names = calloc(x_names_alloc, sizeof(char*)); 148 attributes->values = calloc(x_values_alloc, sizeof(cxmutstr)); 149 150 struct cx_array_reallocator_s re = { .realloc = array_realloc }; 151 152 size_t count = 0; 153 154 char *hash = NULL; 155 156 DavXmlNode *node = xml; 157 for(;node;node=node->next) { 158 if(node->type == DAV_XML_ELEMENT) { 159 if(!strcmp(node->name, "hash")) { 160 hash = dav_xml_getstring(node->children); 161 } else if(!strcmp(node->name, "xattr")) { 162 char *xattr_name = dav_xml_get_attr(node, "name"); 163 if(xattr_name) { 164 char *xname = strdup(xattr_name); 165 cx_array_copy( 166 (void**)&attributes->names, 167 &x_names_size, 168 &x_names_alloc, 169 count, 170 &xname, 171 sizeof(void*), 172 1, 173 &re); 174 175 char *text = dav_xml_getstring(node->children); 176 if(!text) { 177 text = ""; 178 } 179 180 int len = 0; 181 char *val = util_base64decode_len(text, &len); 182 183 cxmutstr value; 184 value.ptr = val; 185 value.length = len; 186 187 cx_array_copy( 188 (void**)&attributes->values, 189 &x_values_size, 190 &x_values_alloc, 191 count, 192 &value, 193 sizeof(cxmutstr), 194 1, 195 &re); 196 197 count++; 198 } 199 } 200 } 201 } 202 203 if(count == 0) { 204 free(attributes->names); 205 free(attributes->values); 206 free(attributes); 207 return NULL; 208 } 209 210 attributes->hash = hash ? strdup(hash) : NULL; 211 attributes->nattr = count; 212 213 return attributes; 214 } 215 216 XAttributes* file_get_attributes( 217 const char *path, 218 xattr_filter_func filter, 219 void *filterdata) 220 { 221 ssize_t nelm = 0; 222 char **attributes = xattr_list(path, &nelm); 223 if(nelm <= 0) { 224 return NULL; 225 } 226 227 XAttributes *xattr = malloc(sizeof(XAttributes)); 228 xattr->nattr = 0; 229 xattr->names = calloc(nelm, sizeof(char*)); 230 xattr->values = calloc(nelm, sizeof(cxmutstr)); 231 232 DAV_SHA_CTX *sha256 = dav_hash_init(); 233 234 size_t nattr = 0; 235 for(int i=0;i<nelm;i++) { 236 if(filter) { 237 // apply filter 238 if(!filter(attributes[i], filterdata)) { 239 // exclude attribute 240 continue; 241 } 242 } 243 244 ssize_t valuelen = 0; 245 char *value = xattr_get(path, attributes[i], &valuelen); 246 if(valuelen >= 0) { 247 dav_hash_update(sha256, attributes[i], strlen(attributes[i])); 248 dav_hash_update(sha256, value, valuelen); 249 // add name and value 250 xattr->names[nattr] = attributes[i]; 251 cxmutstr v; 252 v.ptr = value; 253 v.length = valuelen; 254 xattr->values[nattr] = v; 255 nattr++; 256 } else { 257 // discard not readable attributes 258 free(attributes[i]); 259 } 260 } 261 262 xattr->nattr = nattr; 263 264 unsigned char hash[DAV_SHA256_DIGEST_LENGTH]; 265 dav_hash_final(sha256, hash); 266 xattr->hash = util_hexstr(hash, DAV_SHA256_DIGEST_LENGTH); 267 268 free(attributes); 269 270 if(nattr > 0) { 271 return xattr; 272 } else { 273 xattributes_free(xattr); 274 return NULL; 275 } 276 } 277 278 int resource_set_xattr(DavResource *res, XAttributes *xattr) { 279 if(!xattr || xattr->nattr == 0) { 280 return 0; 281 } 282 283 DavXmlNode *content = dav_xml_createnode_with_text(DAV_PROPS_NS, "hash", xattr->hash); 284 DavXmlNode *last = content; 285 286 for(int i=0;i<xattr->nattr;i++) { 287 DavXmlNode *attr = dav_xml_createnode(DAV_PROPS_NS, "xattr"); 288 dav_xml_add_attr(attr, "name", xattr->names[i]); 289 last->next = attr; 290 last = attr; 291 292 cxmutstr value = xattr->values[i]; 293 if(value.length > 0) { 294 char *encval = util_base64encode(value.ptr, value.length); 295 attr->children = dav_xml_createtextnode(encval); 296 free(encval); 297 } 298 } 299 300 dav_set_property_ns(res, DAV_PROPS_NS, "xattributes", content); 301 302 return 0; 303 } 304 305 void xattributes_free(XAttributes *xattr) { 306 free(xattr->hash); 307 for(int i=0;i<xattr->nattr;i++) { 308 free(xattr->names[i]); 309 free(xattr->values[i].ptr); 310 } 311 free(xattr); 312 } 313 314 char* get_xattr_hash(DavXmlNode *finfo) { 315 DavXmlNode *node = finfo; 316 while(node) { 317 if(node->type == DAV_XML_ELEMENT && !strcmp(node->name, "hash")) { 318 return dav_xml_getstring(node->children); 319 } 320 node = node->next; 321 } 322 return NULL; 323 } 324 325 void finfo_get_values(DavXmlNode *xml, FileInfo *outval) { 326 memset(outval, 0, sizeof(FileInfo)); 327 DavXmlNode *node = xml; 328 while(node) { 329 if(node->type == DAV_XML_ELEMENT) { 330 if(!strcmp(node->name, "mtime")) { 331 char *mtime = dav_xml_getstring(node->children); 332 if(mtime) { 333 outval->last_modified = util_parse_lastmodified(mtime); 334 outval->date_set = TRUE; 335 } 336 } else if(!strcmp(node->name, "mode")) { 337 char *mode_str = dav_xml_getstring(node->children); 338 if(mode_str) { 339 char *end; 340 errno = 0; 341 long int mode = strtol(mode_str, &end, 8); 342 if(errno == 0) { 343 mode &= 07777; 344 outval->mode = mode; 345 outval->mode_set = TRUE; 346 } 347 } 348 } 349 } 350 node = node->next; 351 } 352 353 } 354