521 WebdavResource *resource) |
523 WebdavResource *resource) |
522 { |
524 { |
523 return 0; // NOP |
525 return 0; // NOP |
524 } |
526 } |
525 |
527 |
|
528 |
|
529 /**************************************************************************** |
|
530 * |
|
531 * VFS OPERATION |
|
532 * |
|
533 ****************************************************************************/ |
|
534 |
|
535 WebdavVFSOperation* webdav_vfs_op( |
|
536 Session *sn, |
|
537 Request *rq, |
|
538 WebdavBackend *dav, |
|
539 WSBool precondition) |
|
540 { |
|
541 WebdavVFSOperation *op = pool_malloc(sn->pool, sizeof(WebdavVFSOperation)); |
|
542 if(!op) { |
|
543 return NULL; |
|
544 } |
|
545 ZERO(op, sizeof(WebdavVFSOperation)); |
|
546 |
|
547 op->sn = sn; |
|
548 op->rq = rq; |
|
549 op->dav = dav; |
|
550 op->stat = NULL; |
|
551 op->stat_errno = 0; |
|
552 |
|
553 // create VFS context |
|
554 VFSContext *vfs = vfs_request_context(sn, rq); |
|
555 if(!vfs) { |
|
556 pool_free(sn->pool, op); |
|
557 return NULL; |
|
558 } |
|
559 op->vfs = vfs; |
|
560 |
|
561 char *path = pblock_findkeyval(pb_key_path, rq->vars); |
|
562 op->path = path; |
|
563 |
|
564 return op; |
|
565 } |
|
566 |
|
567 int webdav_vfs_stat(WebdavVFSOperation *op) { |
|
568 if(op->stat) { |
|
569 return 0; |
|
570 } else if(op->stat_errno != 0) { |
|
571 // previous stat failed |
|
572 return 1; |
|
573 } |
|
574 |
|
575 // stat file |
|
576 struct stat sbuf; |
|
577 int ret = vfs_stat(op->vfs, op->path, &sbuf); |
|
578 if(!ret) { |
|
579 // save result in op->stat and in s |
|
580 op->stat = pool_malloc(op->sn->pool, sizeof(struct stat)); |
|
581 if(op->stat) { |
|
582 memcpy(op->stat, &sbuf, sizeof(struct stat)); |
|
583 } else { |
|
584 ret = 1; |
|
585 op->stat_errno = ENOMEM; |
|
586 } |
|
587 } else { |
|
588 op->stat_errno = errno; |
|
589 } |
|
590 |
|
591 return ret; |
|
592 } |
|
593 |
|
594 int webdav_vfs_op_do(WebdavVFSOperation *op, WebdavVFSOpType type) { |
|
595 WSBool exec_vfs = TRUE; |
|
596 |
|
597 // requests for each backends |
|
598 WebdavVFSRequest **requests = pool_calloc( |
|
599 op->sn->pool, |
|
600 webdav_num_backends(op->dav), |
|
601 sizeof(WebdavVFSRequest*)); |
|
602 if(requests == NULL) { |
|
603 return REQ_ABORTED; |
|
604 } |
|
605 |
|
606 int ret = REQ_PROCEED; |
|
607 |
|
608 // call opt_* func for each backend |
|
609 WebdavBackend *dav = op->dav; |
|
610 int called_backends = 0; |
|
611 while(dav) { |
|
612 WebdavVFSRequest *request = NULL; |
|
613 |
|
614 // get vfs operation functions |
|
615 vfs_op_func op_func = NULL; |
|
616 vfs_op_finish_func op_finish_func = NULL; |
|
617 |
|
618 if(type == WEBDAV_VFS_MKDIR) { |
|
619 op_func = dav->opt_mkcol; |
|
620 op_finish_func = dav->opt_mkcol_finish; |
|
621 } else if(type == WEBDAV_VFS_DELETE) { |
|
622 op_func = dav->opt_delete; |
|
623 op_finish_func = dav->opt_delete_finish; |
|
624 } |
|
625 |
|
626 if(op_func || op_finish_func) { |
|
627 // we need a request object |
|
628 request = pool_malloc(op->sn->pool, sizeof(WebdavVFSRequest)); |
|
629 if(!request) { |
|
630 exec_vfs = FALSE; |
|
631 ret = REQ_ABORTED; |
|
632 break; |
|
633 } |
|
634 request->sn = op->sn; |
|
635 request->rq = op->rq; |
|
636 request->path = op->path; |
|
637 request->userdata = NULL; |
|
638 |
|
639 requests[called_backends] = request; |
|
640 } |
|
641 |
|
642 // exec backend func for this operation |
|
643 // this will set 'done' to TRUE, if no further vfs call is required |
|
644 WSBool done = FALSE; |
|
645 called_backends++; |
|
646 if(op_func) { |
|
647 if(op_func(request, &done)) { |
|
648 exec_vfs = FALSE; |
|
649 ret = REQ_ABORTED; |
|
650 break; |
|
651 } |
|
652 } |
|
653 if(done) { |
|
654 exec_vfs = FALSE; |
|
655 } |
|
656 |
|
657 dav = dav->next; |
|
658 } |
|
659 |
|
660 // if needed, call vfs func for this operation |
|
661 if(exec_vfs) { |
|
662 int r = 0; |
|
663 if(type == WEBDAV_VFS_MKDIR) { |
|
664 r = vfs_mkdir(op->vfs, op->path); |
|
665 } else if(type == WEBDAV_VFS_DELETE) { |
|
666 r = webdav_vfs_unlink(op); |
|
667 } |
|
668 |
|
669 if(r) { |
|
670 ret = REQ_ABORTED; |
|
671 } |
|
672 } |
|
673 |
|
674 WSBool success = ret == REQ_PROCEED ? TRUE : FALSE; |
|
675 |
|
676 // finish mkcol (cleanup) by calling opt_*_finish for each backend |
|
677 dav = op->dav; |
|
678 int i = 0; |
|
679 while(dav && i < called_backends) { |
|
680 // get vfs operation functions |
|
681 vfs_op_finish_func op_finish_func = NULL; |
|
682 |
|
683 if(type == WEBDAV_VFS_MKDIR) { |
|
684 op_finish_func = dav->opt_mkcol_finish; |
|
685 } else if(type == WEBDAV_VFS_DELETE) { |
|
686 op_finish_func = dav->opt_delete_finish; |
|
687 } |
|
688 |
|
689 if(op_finish_func) { |
|
690 if(op_finish_func(requests[i], success)) { |
|
691 ret = REQ_ABORTED; // don't exit loop |
|
692 } |
|
693 } |
|
694 |
|
695 dav = dav->next; |
|
696 i++; |
|
697 } |
|
698 |
|
699 return ret; |
|
700 } |
|
701 |
|
702 int webdav_vfs_unlink(WebdavVFSOperation *op) { |
|
703 // stat the file first, to check if the file is a directory |
|
704 // deletion of simple files can be done just here, |
|
705 // whereas deleting directories is more complicated |
|
706 if(webdav_vfs_stat(op)) { |
|
707 return 1; // error |
|
708 } else { |
|
709 int r = 0; |
|
710 if(!S_ISDIR(op->stat->st_mode)) { |
|
711 return vfs_unlink(op->vfs, op->path); |
|
712 } |
|
713 } |
|
714 |
|
715 // delete directory: |
|
716 |
|
717 |
|
718 |
|
719 return 0; |
|
720 } |