src/server/webdav/webdav.c

changeset 415
d938228c382e
parent 414
99a34860c105
child 453
4586d534f9b5
equal deleted inserted replaced
414:99a34860c105 415:d938228c382e
28 28
29 #include <stdio.h> 29 #include <stdio.h>
30 #include <stdlib.h> 30 #include <stdlib.h>
31 #include <string.h> 31 #include <string.h>
32 32
33 #include <ucx/buffer.h> 33 #include <cx/buffer.h>
34 #include <ucx/list.h> 34 #include <cx/list.h>
35 #include <cx/linked_list.h>
36 #include <cx/hash_map.h>
37 #include <cx/printf.h>
35 38
36 #include "webdav.h" 39 #include "webdav.h"
37 40
38 #include "search.h" 41 #include "search.h"
39 #include "versioning.h" 42 #include "versioning.h"
51 /* 54 /*
52 * http method fptr mapping 55 * http method fptr mapping
53 * key: http method name (string) 56 * key: http method name (string)
54 * value: SAF fptr 57 * value: SAF fptr
55 */ 58 */
56 static UcxMap *method_handler_map; 59 static CxMap *method_handler_map;
57 60
58 /* 61 /*
59 * webdav backend types 62 * webdav backend types
60 * key: backend name (string) 63 * key: backend name (string)
61 * value: WebdavBackend* 64 * value: WebdavBackend*
62 */ 65 */
63 static UcxMap *webdav_type_map; 66 static CxMap *webdav_type_map;
64 67
65 static WebdavBackend default_backend; 68 static WebdavBackend default_backend;
66 69
67 static WSNamespace dav_namespace; 70 static WSNamespace dav_namespace;
68 71
87 90
88 int webdav_register_backend(const char *name, webdav_init_func webdavInit, webdav_create_func webdavCreate) { 91 int webdav_register_backend(const char *name, webdav_init_func webdavInit, webdav_create_func webdavCreate) {
89 WebdavType *webdavType = malloc(sizeof(WebdavType)); 92 WebdavType *webdavType = malloc(sizeof(WebdavType));
90 webdavType->init = webdavInit; 93 webdavType->init = webdavInit;
91 webdavType->create = webdavCreate; 94 webdavType->create = webdavCreate;
92 return ucx_map_cstr_put(webdav_type_map, name, webdavType); 95 return cxMapPut(webdav_type_map, cx_hash_key_str(name), webdavType);
93 } 96 }
94 97
95 WebdavType* webdav_get_type(scstr_t dav_class) { 98 WebdavType* webdav_get_type(cxstring dav_class) {
96 return ucx_map_sstr_get(webdav_type_map, dav_class); 99 return cxMapGet(webdav_type_map, cx_hash_key_bytes((unsigned const char *)dav_class.ptr, dav_class.length));
97 } 100 }
98 101
99 void* webdav_init_backend(ServerConfiguration *cfg, pool_handle_t *pool, WebdavType *dav_class, WSConfigNode *config, int *error) { 102 void* webdav_init_backend(ServerConfiguration *cfg, pool_handle_t *pool, WebdavType *dav_class, WSConfigNode *config, int *error) {
100 *error = 0; 103 *error = 0;
101 if(dav_class->init) { 104 if(dav_class->init) {
108 return NULL; 111 return NULL;
109 } 112 }
110 } 113 }
111 114
112 WebdavBackend* webdav_create(Session *sn, Request *rq, const char *dav_class, pblock *pb, void *initData) { 115 WebdavBackend* webdav_create(Session *sn, Request *rq, const char *dav_class, pblock *pb, void *initData) {
113 WebdavType *webdavType = ucx_map_cstr_get(webdav_type_map, dav_class); 116 WebdavType *webdavType = cxMapGet(webdav_type_map, cx_hash_key_str(dav_class));
114 if(!webdavType) { 117 if(!webdavType) {
115 log_ereport(LOG_MISCONFIG, "webdav_create: unkown dav type %s", dav_class); 118 log_ereport(LOG_MISCONFIG, "webdav_create: unkown dav type %s", dav_class);
116 return NULL; 119 return NULL;
117 } 120 }
118 121
125 if(webdav_is_initialized) { 128 if(webdav_is_initialized) {
126 return REQ_NOACTION; 129 return REQ_NOACTION;
127 } 130 }
128 webdav_is_initialized = TRUE; 131 webdav_is_initialized = TRUE;
129 132
130 webdav_type_map = ucx_map_new(8); 133 webdav_type_map = cxHashMapCreate(cxDefaultAllocator, 8);
131 if(!webdav_type_map) { 134 if(!webdav_type_map) {
132 return REQ_ABORTED; 135 return REQ_ABORTED;
133 } 136 }
134 137
135 method_handler_map = ucx_map_new(64); 138 method_handler_map = cxHashMapCreate(cxDefaultAllocator, 64);
136 if(!method_handler_map) { 139 if(!method_handler_map) {
137 return REQ_ABORTED; 140 return REQ_ABORTED;
138 } 141 }
139 142
140 init_default_backend(); 143 init_default_backend();
141 ucx_map_cstr_put(webdav_type_map, "default", &default_backend); 144 cxMapPut(webdav_type_map, cx_hash_key_str("default"), &default_backend);
142 145
143 ucx_map_cstr_put(method_handler_map, "OPTIONS", webdav_options); 146 cxMapPut(method_handler_map, cx_hash_key_str("OPTIONS"), webdav_options);
144 ucx_map_cstr_put(method_handler_map, "PROPFIND", webdav_propfind); 147 cxMapPut(method_handler_map, cx_hash_key_str("PROPFIND"), webdav_propfind);
145 ucx_map_cstr_put(method_handler_map, "PROPPATCH", webdav_proppatch); 148 cxMapPut(method_handler_map, cx_hash_key_str("PROPPATCH"), webdav_proppatch);
146 ucx_map_cstr_put(method_handler_map, "MKCOL", webdav_mkcol); 149 cxMapPut(method_handler_map, cx_hash_key_str("MKCOL"), webdav_mkcol);
147 ucx_map_cstr_put(method_handler_map, "POST", webdav_post); 150 cxMapPut(method_handler_map, cx_hash_key_str("POST"), webdav_post);
148 ucx_map_cstr_put(method_handler_map, "DELETE", webdav_delete); 151 cxMapPut(method_handler_map, cx_hash_key_str("DELETE"), webdav_delete);
149 ucx_map_cstr_put(method_handler_map, "PUT", webdav_put); 152 cxMapPut(method_handler_map, cx_hash_key_str("PUT"), webdav_put);
150 ucx_map_cstr_put(method_handler_map, "COPY", webdav_copy); 153 cxMapPut(method_handler_map, cx_hash_key_str("COPY"), webdav_copy);
151 ucx_map_cstr_put(method_handler_map, "MOVE", webdav_move); 154 cxMapPut(method_handler_map, cx_hash_key_str("MOVE"), webdav_move);
152 ucx_map_cstr_put(method_handler_map, "LOCK", webdav_lock); 155 cxMapPut(method_handler_map, cx_hash_key_str("LOCK"), webdav_lock);
153 ucx_map_cstr_put(method_handler_map, "UNLOCK", webdav_unlock); 156 cxMapPut(method_handler_map, cx_hash_key_str("UNLOCK"), webdav_unlock);
154 ucx_map_cstr_put(method_handler_map, "REPORT", webdav_report); 157 cxMapPut(method_handler_map, cx_hash_key_str("REPORT"), webdav_report);
155 ucx_map_cstr_put(method_handler_map, "ACL", webdav_acl); 158 cxMapPut(method_handler_map, cx_hash_key_str("ACL"), webdav_acl);
156 159
157 ucx_map_cstr_put(method_handler_map, "SEARCH", webdav_search); 160 cxMapPut(method_handler_map, cx_hash_key_str("SEARCH"), webdav_search);
158 161
159 ucx_map_cstr_put(method_handler_map, "VERSION-CONTROL", webdav_version_control); 162 cxMapPut(method_handler_map, cx_hash_key_str("VERSION-CONTROL"), webdav_version_control);
160 ucx_map_cstr_put(method_handler_map, "CHECKOUT", webdav_checkout); 163 cxMapPut(method_handler_map, cx_hash_key_str("CHECKOUT"), webdav_checkout);
161 ucx_map_cstr_put(method_handler_map, "CHECKIN", webdav_checkin); 164 cxMapPut(method_handler_map, cx_hash_key_str("CHECKIN"), webdav_checkin);
162 ucx_map_cstr_put(method_handler_map, "UNCHECKOUT", webdav_uncheckout); 165 cxMapPut(method_handler_map, cx_hash_key_str("UNCHECKOUT"), webdav_uncheckout);
163 ucx_map_cstr_put(method_handler_map, "MKWORKSPACE", webdav_mkworkspace); 166 cxMapPut(method_handler_map, cx_hash_key_str("MKWORKSPACE"), webdav_mkworkspace);
164 ucx_map_cstr_put(method_handler_map, "UPDATE", webdav_update); 167 cxMapPut(method_handler_map, cx_hash_key_str("UPDATE"), webdav_update);
165 ucx_map_cstr_put(method_handler_map, "LABEL", webdav_label); 168 cxMapPut(method_handler_map, cx_hash_key_str("LABEL"), webdav_label);
166 ucx_map_cstr_put(method_handler_map, "MERGE", webdav_merge); 169 cxMapPut(method_handler_map, cx_hash_key_str("MERGE"), webdav_merge);
167 170
168 dav_namespace.href = (xmlChar*)"DAV:"; 171 dav_namespace.href = (xmlChar*)"DAV:";
169 dav_namespace.prefix = (xmlChar*)"D"; 172 dav_namespace.prefix = (xmlChar*)"D";
170 173
171 dav_resourcetype_empty.namespace = &dav_namespace; 174 dav_resourcetype_empty.namespace = &dav_namespace;
189 protocol_status(sn, rq, 500, NULL); 192 protocol_status(sn, rq, 500, NULL);
190 return REQ_ABORTED; 193 return REQ_ABORTED;
191 } 194 }
192 char *method = pblock_findkeyval(pb_key_method, rq->reqpb); 195 char *method = pblock_findkeyval(pb_key_method, rq->reqpb);
193 196
194 FuncPtr saf = (FuncPtr)ucx_map_cstr_get(method_handler_map, method); 197 FuncPtr saf = (FuncPtr)cxMapGet(method_handler_map, cx_hash_key_str(method));
195 if(!saf) { 198 if(!saf) {
196 return REQ_NOACTION; 199 return REQ_NOACTION;
197 } 200 }
198 201
199 return saf(pb, sn, rq); 202 return saf(pb, sn, rq);
200 } 203 }
201 204
202 UcxBuffer* rqbody2buffer(Session *sn, Request *rq) { 205 int rqbody2buffer(Session *sn, Request *rq, CxBuffer *buf) {
203 if(!sn->inbuf) { 206 if(!sn->inbuf) {
204 //request body required, set http response code 207 //request body required, set http response code
205 protocol_status(sn, rq, 400, NULL); 208 protocol_status(sn, rq, 400, NULL);
206 return NULL; 209 return 1;
207 } 210 }
208 211
209 UcxBuffer *buf = ucx_buffer_new( 212 CxAllocator *a = pool_allocator(sn->pool);
210 NULL, 213 if(cxBufferInit(buf, NULL, sn->inbuf->maxsize, a, CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) {
211 sn->inbuf->maxsize,
212 UCX_BUFFER_AUTOEXTEND);
213 if(!buf) {
214 protocol_status(sn, rq, 500, NULL); 214 protocol_status(sn, rq, 500, NULL);
215 return NULL; 215 return 1;
216 } 216 }
217 217
218 char in[2048]; 218 char in[2048];
219 int r; 219 int r;
220 while((r = netbuf_getbytes(sn->inbuf, in, 2048)) > 0) { 220 while((r = netbuf_getbytes(sn->inbuf, in, 2048)) > 0) {
221 if(ucx_buffer_write(in, 1, r, buf) != r) { 221 if(cxBufferWrite(in, 1, r, buf) != r) {
222 protocol_status(sn, rq, 500, NULL); 222 protocol_status(sn, rq, 500, NULL);
223 ucx_buffer_free(buf); 223 cxBufferDestroy(buf);
224 return NULL; 224 return 1;
225 } 225 }
226 } 226 }
227 227
228 return buf; 228 return 0;
229 } 229 }
230 230
231 int webdav_options(pblock *pb, Session *sn, Request *rq) { 231 int webdav_options(pblock *pb, Session *sn, Request *rq) {
232 return REQ_ABORTED; 232 return REQ_ABORTED;
233 } 233 }
252 return REQ_ABORTED; 252 return REQ_ABORTED;
253 } 253 }
254 } 254 }
255 } 255 }
256 256
257 UcxBuffer *reqbody = rqbody2buffer(sn, rq); 257 CxBuffer reqbody;
258 if(!reqbody) { 258 if(rqbody2buffer(sn, rq, &reqbody)) {
259 return REQ_ABORTED; 259 return REQ_ABORTED;
260 } 260 }
261 261
262 int error = 0; 262 int error = 0;
263 WebdavPropfindRequest *propfind = propfind_parse( 263 WebdavPropfindRequest *propfind = propfind_parse(
264 sn, 264 sn,
265 rq, 265 rq,
266 reqbody->space, 266 reqbody.space,
267 reqbody->size, 267 reqbody.size,
268 &error); 268 &error);
269 ucx_buffer_free(reqbody); 269 cxBufferDestroy(&reqbody);
270 if(!propfind) { 270 if(!propfind) {
271 log_ereport(LOG_FAILURE, "webdav-propfind: %s", propfind_error2str(error)); 271 log_ereport(LOG_FAILURE, "webdav-propfind: %s", propfind_error2str(error));
272 return REQ_ABORTED; 272 return REQ_ABORTED;
273 } 273 }
274 274
316 int webdav_propfind_init( 316 int webdav_propfind_init(
317 WebdavBackend *dav, 317 WebdavBackend *dav,
318 WebdavPropfindRequest *propfind, 318 WebdavPropfindRequest *propfind,
319 const char *path, 319 const char *path,
320 const char *uri, 320 const char *uri,
321 UcxList **out_req) 321 WebdavPropfindRequestList **out_req)
322 { 322 {
323 pool_handle_t *pool = propfind->sn->pool; 323 pool_handle_t *pool = propfind->sn->pool;
324 UcxAllocator *a = session_get_allocator(propfind->sn); 324 CxAllocator *a = pool_allocator(pool);
325 325
326 // list of individual WebdavPropfindRequest objects for each Backend 326 // list of individual WebdavPropfindRequest objects for each Backend
327 UcxList *requestObjects = NULL; 327 WebdavPropfindRequestList *requestObjectsBegin = NULL;
328 WebdavPropfindRequestList *requestObjectsEnd = NULL;
328 329
329 // new properties after init, start with clone of original plist 330 // new properties after init, start with clone of original plist
330 WebdavPList *newProp = webdav_plist_clone(pool, propfind->properties); 331 WebdavPList *newProp = webdav_plist_clone(pool, propfind->properties);
331 size_t newPropCount = propfind->propcount; 332 size_t newPropCount = propfind->propcount;
332 333
345 pReq->properties = newProp; 346 pReq->properties = newProp;
346 pReq->propcount = newPropCount; 347 pReq->propcount = newPropCount;
347 pReq->dav = davList; 348 pReq->dav = davList;
348 349
349 // add new WebdavPropfindRequest object to list for later use 350 // add new WebdavPropfindRequest object to list for later use
350 requestObjects = ucx_list_append_a(a, requestObjects, pReq); 351 WebdavPropfindRequestList *reqListElm = pool_malloc(pool, sizeof(WebdavPropfindRequestList));
351 if(!requestObjects) { 352 if(!reqListElm) {
352 return REQ_ABORTED; // OOM 353 return REQ_ABORTED; // OOM
353 } 354 }
355 reqListElm->propfind = pReq;
356 reqListElm->next = NULL;
357 cx_linked_list_add(
358 (void**)&requestObjectsBegin,
359 (void**)&requestObjectsEnd,
360 -1,
361 offsetof(WebdavPropfindRequestList, next),
362 reqListElm);
354 363
355 // create plist copy as out-plist for init 364 // create plist copy as out-plist for init
356 newProp = webdav_plist_clone(pool, newProp); 365 newProp = webdav_plist_clone(pool, newProp);
357 366
358 // run init: this can generate a new properties list (newProp) 367 // run init: this can generate a new properties list (newProp)
364 newPropCount = webdav_plist_size(newProp); 373 newPropCount = webdav_plist_size(newProp);
365 374
366 davList = davList->next; 375 davList = davList->next;
367 } 376 }
368 377
369 *out_req = requestObjects; 378 *out_req = requestObjectsBegin;
370 return REQ_PROCEED; 379 return REQ_PROCEED;
371 } 380 }
372 381
373 int webdav_propfind_do( 382 int webdav_propfind_do(
374 WebdavBackend *dav, 383 WebdavBackend *dav,
383 392
384 // VFS settings are only taken from the first backend 393 // VFS settings are only taken from the first backend
385 uint32_t settings = dav->settings; 394 uint32_t settings = dav->settings;
386 395
387 // list of individual WebdavPropfindRequest objects for each Backend 396 // list of individual WebdavPropfindRequest objects for each Backend
388 UcxList *requestObjects = NULL; 397 WebdavPropfindRequestList *requestObjects = NULL;
389 398
390 // Initialize all Webdav Backends 399 // Initialize all Webdav Backends
391 if(webdav_propfind_init(dav, propfind, path, uri, &requestObjects)) { 400 if(webdav_propfind_init(dav, propfind, path, uri, &requestObjects)) {
392 return REQ_ABORTED; 401 return REQ_ABORTED;
393 } 402 }
478 return REQ_ABORTED; 487 return REQ_ABORTED;
479 } 488 }
480 } 489 }
481 } 490 }
482 491
483 UcxBuffer *reqbody = rqbody2buffer(sn, rq); 492 CxBuffer reqbody;
484 if(!reqbody) { 493 if(rqbody2buffer(sn, rq, &reqbody)) {
485 // most likely OOM 494 // most likely OOM
486 return REQ_ABORTED; 495 return REQ_ABORTED;
487 } 496 }
488 497
489 int error = 0; 498 int error = 0;
490 WebdavProppatchRequest *proppatch = proppatch_parse( 499 WebdavProppatchRequest *proppatch = proppatch_parse(
491 sn, 500 sn,
492 rq, 501 rq,
493 reqbody->space, 502 reqbody.space,
494 reqbody->size, 503 reqbody.size,
495 &error); 504 &error);
496 ucx_buffer_free(reqbody); 505 cxBufferDestroy(&reqbody);
497 if(!proppatch) { 506 if(!proppatch) {
498 log_ereport(LOG_FAILURE, "webdav-proppatch: %s", proppatch_error2str(error)); 507 log_ereport(LOG_FAILURE, "webdav-proppatch: %s", proppatch_error2str(error));
499 return REQ_ABORTED; 508 return REQ_ABORTED;
500 } 509 }
501 510
585 } 594 }
586 595
587 typedef struct DeleteFile { 596 typedef struct DeleteFile {
588 char *path; 597 char *path;
589 struct stat s; 598 struct stat s;
599 struct DeleteFile *prev;
600 struct DeleteFile *next;
590 } DeleteFile; 601 } DeleteFile;
591 602
592 typedef struct DeleteLists { 603 typedef struct DeleteLists {
593 UcxAllocator *a; 604 CxAllocator *a;
594 UcxList *dirs_begin; 605 DeleteFile *dirs_begin;
595 UcxList *dirs_end; 606 DeleteFile *dirs_end;
596 UcxList *files_begin; 607 DeleteFile *files_begin;
597 UcxList *files_end; 608 DeleteFile *files_end;
598 } DeleteOp; 609 } DeleteOp;
599 610
600 static int deletelist_add( 611 static int deletelist_add(
601 VFSContext *vfs, 612 VFSContext *vfs,
602 const char *href, 613 const char *href,
606 void *userdata) 617 void *userdata)
607 { 618 {
608 DeleteOp *op = userdata; 619 DeleteOp *op = userdata;
609 620
610 // create object for this file 621 // create object for this file
611 DeleteFile *file = almalloc(op->a, sizeof(DeleteFile)); 622 DeleteFile *file = cxMalloc(op->a, sizeof(DeleteFile));
612 if(!file) { 623 if(!file) {
613 return 1; 624 return 1;
614 } 625 }
615 file->path = sstrdup_a(op->a, sstr((char*)path)).ptr; 626 file->path = cx_strdup_a(op->a, cx_str((char*)path)).ptr;
616 if(!file->path) { 627 if(!file->path) {
617 return 1; 628 return 1;
618 } 629 }
619 file->s = *s; 630 file->s = *s;
631 file->next = NULL;
620 632
621 // determine which list to use 633 // determine which list to use
622 UcxList **begin; 634 DeleteFile **begin;
623 UcxList **end; 635 DeleteFile **end;
624 if(S_ISDIR(s->st_mode)) { 636 if(S_ISDIR(s->st_mode)) {
625 begin = &op->dirs_begin; 637 begin = &op->dirs_begin;
626 end = &op->dirs_end; 638 end = &op->dirs_end;
627 } else { 639 } else {
628 begin = &op->files_begin; 640 begin = &op->files_begin;
629 end = &op->files_end; 641 end = &op->files_end;
630 } 642 }
631 643
632 // add file to list 644 // add file to list
633 UcxList *elm = ucx_list_append_a(op->a, NULL, file); 645 cx_linked_list_add(
634 if(!elm) { 646 (void**)begin, (void**)end,
635 alfree(op->a, file->path); // at least do some cleanup, although it 647 offsetof(DeleteFile, prev), offsetof(DeleteFile, next),
636 alfree(op->a, file); // isn't really necessary 648 file);
637 return 1;
638 }
639 if(*begin == NULL) {
640 *begin = elm;
641 *end = elm;
642 } else {
643 ucx_list_concat(*end, elm);
644 *end = elm;
645 }
646 649
647 return 0; 650 return 0;
648 } 651 }
649 652
650 static int webdav_delete_collection(WebdavVFSOperation *op) 653 static int webdav_delete_collection(WebdavVFSOperation *op)
651 { 654 {
652 DeleteOp del; 655 DeleteOp del;
653 ZERO(&del, sizeof(DeleteOp)); 656 ZERO(&del, sizeof(DeleteOp));
654 del.a = session_get_allocator(op->sn); 657 del.a = pool_allocator(op->sn->pool);
655 658
656 // get a list of all files 659 // get a list of all files
657 if(webdav_op_iterate_children(op->vfs, -1, NULL, op->path, 660 if(webdav_op_iterate_children(op->vfs, -1, NULL, op->path,
658 deletelist_add, &del)) 661 deletelist_add, &del))
659 { 662 {
662 665
663 // add root to list of dir list 666 // add root to list of dir list
664 DeleteFile root; 667 DeleteFile root;
665 root.path = op->path; 668 root.path = op->path;
666 root.s = *op->stat; 669 root.s = *op->stat;
667 UcxList root_elm; 670 root.prev = NULL;
668 root_elm.data = &root; 671 root.next = del.dirs_begin;
669 root_elm.prev = NULL;
670 root_elm.next = del.dirs_begin;
671 672
672 if(del.dirs_begin) { 673 if(del.dirs_begin) {
673 del.dirs_begin->prev = &root_elm; 674 del.dirs_begin->prev = &root;
674 del.dirs_begin = &root_elm;
675 } else { 675 } else {
676 del.dirs_begin = &root_elm; 676 del.dirs_end = &root;
677 del.dirs_end = &root_elm; 677 }
678 } 678 del.dirs_begin = &root;
679 679
680 // delete files first 680 // delete files first
681 UCX_FOREACH(elm, del.files_begin) { 681 for(DeleteFile *file=del.files_begin;file;file=file->next) {
682 DeleteFile *file = elm->data;
683 WebdavVFSOperation sub = webdav_vfs_sub_op(op, file->path, &file->s); 682 WebdavVFSOperation sub = webdav_vfs_sub_op(op, file->path, &file->s);
684 if(webdav_vfs_op_do(&sub, WEBDAV_VFS_DELETE)) { 683 if(webdav_vfs_op_do(&sub, WEBDAV_VFS_DELETE)) {
685 return 1; 684 return 1;
686 } 685 }
687 } 686 }
688 687
689 // delete directories, reverse order 688 // delete directories, reverse order
690 for(UcxList *elm=del.dirs_end;elm;elm=elm->prev) { 689 for(DeleteFile *file=del.dirs_end;file;file=file->prev) {
691 DeleteFile *file = elm->data;
692 WebdavVFSOperation sub = webdav_vfs_sub_op(op, file->path, &file->s); 690 WebdavVFSOperation sub = webdav_vfs_sub_op(op, file->path, &file->s);
693 if(webdav_vfs_op_do(&sub, WEBDAV_VFS_DELETE)) { 691 if(webdav_vfs_op_do(&sub, WEBDAV_VFS_DELETE)) {
694 return 1; 692 return 1;
695 } 693 }
696 } 694 }
911 909
912 910
913 911
914 /* ------------------------------ Utils ------------------------------ */ 912 /* ------------------------------ Utils ------------------------------ */
915 913
916 UcxKey webdav_property_key(const char *ns, const char *name) { 914 CxHashKey webdav_property_key(const char *ns, const char *name) {
917 UcxKey key; 915 CxHashKey key;
918 sstr_t data = ucx_sprintf("%s\n%s", name, ns); 916 cxmutstr data = cx_asprintf("%s\n%s", name, ns);
919 key.data = data.ptr; 917 key.data.str = data.ptr;
920 key.len = data.length; 918 key.len = data.length;
921 key.hash = ucx_hash(data.ptr, data.length); 919 cx_hash_murmur(&key);
922 return key; 920 return key;
923 } 921 }
924
925
926 922
927 923
928 /* ------------------------------ public API ------------------------------ */ 924 /* ------------------------------ public API ------------------------------ */
929 925
930 int webdav_getdepth(Request *rq) { 926 int webdav_getdepth(Request *rq) {

mercurial