365 op->dav = dav; |
375 op->dav = dav; |
366 op->sn = sn; |
376 op->sn = sn; |
367 op->rq = rq; |
377 op->rq = rq; |
368 op->reqprops = NULL; |
378 op->reqprops = NULL; |
369 op->response = response; |
379 op->response = response; |
|
380 op->proppatch = proppatch; |
370 op->response_close = webdav_op_proppatch_close_resource; |
381 op->response_close = webdav_op_proppatch_close_resource; |
371 response->op = op; |
382 response->op = op; |
372 |
383 |
373 return op; |
384 return op; |
|
385 } |
|
386 |
|
387 |
|
388 |
|
389 int webdav_op_proppatch( |
|
390 WebdavOperation *op, |
|
391 const char *href, |
|
392 const char *path) |
|
393 { |
|
394 WebdavProppatchRequest *orig_request = op->proppatch; |
|
395 UcxAllocator *a = session_get_allocator(op->sn); |
|
396 |
|
397 // create WebdavResource object for the requested resource |
|
398 WebdavResource *resource = op->response->addresource(op->response, href); |
|
399 if(!resource) { |
|
400 return REQ_ABORTED; |
|
401 } |
|
402 |
|
403 VFSContext *ctx = NULL; |
|
404 VFSFile *file = NULL; |
|
405 |
|
406 // requests for each backends |
|
407 WebdavProppatchRequest **requests = pool_calloc( |
|
408 op->sn->pool, |
|
409 webdav_num_backends(op->dav), |
|
410 sizeof(WebdavProppatchRequest*)); |
|
411 if(requests == NULL) { |
|
412 return REQ_ABORTED; |
|
413 } |
|
414 |
|
415 WebdavPList *prev_set = orig_request->set; |
|
416 WebdavPList *prev_remove = orig_request->remove; |
|
417 size_t set_count = orig_request->setcount; |
|
418 size_t remove_count = orig_request->removecount; |
|
419 |
|
420 int ret = REQ_PROCEED; |
|
421 |
|
422 // iterate backends and execute proppatch_do |
|
423 WebdavBackend *dav = op->dav; |
|
424 size_t numrequests = 0; |
|
425 while(dav) { |
|
426 WebdavPList *set = webdav_plist_clone_s( |
|
427 op->sn->pool, |
|
428 prev_set, |
|
429 &set_count); |
|
430 WebdavPList *remove = webdav_plist_clone_s( |
|
431 op->sn->pool, |
|
432 prev_remove, |
|
433 &remove_count); |
|
434 if((prev_set && !set) || (prev_remove && !remove)) { |
|
435 // clone failed, OOM |
|
436 ret = REQ_ABORTED; |
|
437 break; |
|
438 } |
|
439 |
|
440 // create new WebdavProppatchRequest object for this backend |
|
441 WebdavProppatchRequest *req = pool_malloc( |
|
442 op->sn->pool, |
|
443 sizeof(WebdavProppatchRequest)); |
|
444 memcpy(req, orig_request, sizeof(WebdavProppatchRequest)); |
|
445 req->set = set; |
|
446 req->setcount = set_count; |
|
447 req->remove = remove; |
|
448 req->removecount = remove_count; |
|
449 req->userdata = NULL; |
|
450 |
|
451 // check if we need to open the file because the backend want's it |
|
452 if(!file && (dav->settings & WS_WEBDAV_PROPPATCH_USE_VFS) |
|
453 == WS_WEBDAV_PROPPATCH_USE_VFS) |
|
454 { |
|
455 ctx = vfs_request_context(op->sn, op->rq); |
|
456 if(!ctx) { |
|
457 ret = REQ_ABORTED; |
|
458 break; |
|
459 } |
|
460 |
|
461 file = vfs_open(ctx, path, O_RDONLY); |
|
462 if(!file) { |
|
463 protocol_status( |
|
464 op->sn, |
|
465 op->rq, |
|
466 util_errno2status(ctx->vfs_errno), |
|
467 NULL); |
|
468 ret = REQ_ABORTED; |
|
469 } |
|
470 } |
|
471 |
|
472 // execute proppatch_do |
|
473 if(dav->proppatch_do(req, resource, file, &set, &remove)) { |
|
474 // return later, because we need do execute proppatch_finish |
|
475 // for all successfully called backends |
|
476 ret = REQ_ABORTED; |
|
477 break; |
|
478 } |
|
479 |
|
480 // proppatch_do should remove all handled props from set and remove |
|
481 // in the next iteration, the backend must use these reduced lists |
|
482 prev_set = set; |
|
483 prev_remove = remove; |
|
484 |
|
485 requests[numrequests++] = req; |
|
486 |
|
487 // continue with next backend |
|
488 dav = dav->next; |
|
489 } |
|
490 |
|
491 WSBool commit = FALSE; |
|
492 if(ret == REQ_PROCEED && resource->err == 0) { |
|
493 // no errors, no properties with errors -> save the changes |
|
494 commit = TRUE; |
|
495 } |
|
496 |
|
497 // call proppatch_finish for each successfully called proppatch_do |
|
498 dav = op->dav; |
|
499 int i = 0; |
|
500 while(dav && i < numrequests) { |
|
501 if(dav->proppatch_finish(requests[i], resource, file, commit)) { |
|
502 ret = REQ_ABORTED; |
|
503 } |
|
504 i++; |
|
505 dav = dav->next; |
|
506 } |
|
507 |
|
508 if(file) { |
|
509 vfs_close(file); |
|
510 } |
|
511 |
|
512 if(resource->close(resource)) { |
|
513 ret = REQ_ABORTED; |
|
514 } |
|
515 |
|
516 return ret; |
374 } |
517 } |
375 |
518 |
376 int webdav_op_proppatch_close_resource( |
519 int webdav_op_proppatch_close_resource( |
377 WebdavOperation *op, |
520 WebdavOperation *op, |
378 WebdavResource *resource) |
521 WebdavResource *resource) |
379 { |
522 { |
380 return 0; |
523 return 0; // NOP |
381 } |
524 } |
382 |
525 |