Apache HTTPD
repos.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18** DAV filesystem-based repository provider
19*/
20
21#include "apr.h"
22#include "apr_file_io.h"
23#include "apr_strings.h"
24#include "apr_buckets.h"
25
26#if APR_HAVE_UNISTD_H
27#include <unistd.h> /* for getpid() */
28#endif
29
30#include "httpd.h"
31#include "http_log.h"
32#include "http_protocol.h" /* for ap_set_* (in dav_fs_set_headers) */
33#include "http_request.h" /* for ap_update_mtime() */
34
35#include "mod_dav.h"
36#include "repos.h"
37
39
40/* to assist in debugging mod_dav's GET handling */
41#define DEBUG_GET_HANDLER 0
42
43#define DAV_FS_COPY_BLOCKSIZE 16384 /* copy 16k at a time */
44
45/* context needed to identify a resource */
47 apr_pool_t *pool; /* memory storage pool associated with request */
48 const char *pathname; /* full pathname to resource */
49 apr_finfo_t finfo; /* filesystem info */
51};
52
53/* private context for doing a filesystem walk */
54typedef struct {
55 /* the input walk parameters */
57
58 /* reused as we walk */
60
65
66 /* MOVE/COPY need a secondary path */
70
72
74
75typedef struct {
76 int is_move; /* is this a MOVE? */
77 dav_buffer work_buf; /* handy buffer for copymove_file() */
78
79 /* CALLBACK: this is a secondary resource managed specially for us */
81
82 /* copied from dav_walk_params (they are invariant across the walk) */
85
87
88/* an internal WALKTYPE to walk hidden files (the .DAV directory) */
89#define DAV_WALKTYPE_HIDDEN 0x4000
90
91/* an internal WALKTYPE to call collections (again) after their contents */
92#define DAV_WALKTYPE_POSTFIX 0x8000
93
94#define DAV_CALLTYPE_POSTFIX 1000 /* a private call type */
95
96
97/* pull this in from the other source file */
99
100/* forward-declare the hook structures */
103
104/*
105** The namespace URIs that we use. This list and the enumeration must
106** stay in sync.
107*/
108static const char * const dav_fs_namespace_uris[] =
109{
110 "DAV:",
111 "http://apache.org/dav/props/",
112
113 NULL /* sentinel */
114};
115enum {
116 DAV_FS_URI_DAV, /* the DAV: namespace URI */
117 DAV_FS_URI_MYPROPS /* the namespace URI for our custom props */
119
120/*
121** Does this platform support an executable flag?
122**
123** ### need a way to portably abstract this query
124**
125** DAV_FINFO_MASK gives the appropriate mask to use for the stat call
126** used to get file attributes.
127*/
128#ifndef WIN32
129#define DAV_FS_HAS_EXECUTABLE
130#define DAV_FINFO_MASK (APR_FINFO_LINK | APR_FINFO_TYPE | APR_FINFO_INODE | \
131 APR_FINFO_SIZE | APR_FINFO_CTIME | APR_FINFO_MTIME | \
132 APR_FINFO_PROT)
133#else
134/* as above, but without APR_FINFO_PROT */
135#define DAV_FINFO_MASK (APR_FINFO_LINK | APR_FINFO_TYPE | APR_FINFO_INODE | \
136 APR_FINFO_SIZE | APR_FINFO_CTIME | APR_FINFO_MTIME)
137#endif
138
139/*
140** The single property that we define (in the DAV_FS_URI_MYPROPS namespace)
141*/
142#define DAV_PROPID_FS_executable 1
143
144/*
145 * prefix for temporary files
146 */
147#define DAV_FS_TMP_PREFIX ".davfs.tmp"
148
150{
151 /* standard DAV properties */
152 {
154 "creationdate",
156 0
157 },
158 {
160 "getcontentlength",
162 0
163 },
164 {
166 "getetag",
168 0
169 },
170 {
172 "getlastmodified",
174 0
175 },
176
177 /* our custom properties */
178 {
180 "executable",
182 0 /* handled special in dav_fs_is_writable */
183 },
184
185 { 0 } /* sentinel */
186};
187
194
195
196/* define the dav_stream structure for our use */
200 const char *pathname; /* we may need to remove it at close time */
201 char *temppath;
203};
204
205/* returns an appropriate HTTP status code given an APR status code for a
206 * failed I/O operation. ### use something besides 500? */
207#define MAP_IO2HTTP(e) (APR_STATUS_IS_ENOSPC(e) ? HTTP_INSUFFICIENT_STORAGE : \
208 APR_STATUS_IS_ENOENT(e) ? HTTP_CONFLICT : \
209 HTTP_INTERNAL_SERVER_ERROR)
210
211/* forward declaration for internal treewalkers */
212static dav_error * dav_fs_walk(const dav_walk_params *params, int depth,
213 dav_response **response);
215 int depth, int is_move,
216 const dav_resource *root_dst,
217 dav_response **response);
218
219/* --------------------------------------------------------------------
220**
221** PRIVATE REPOSITORY FUNCTIONS
222*/
224{
225 return resource->info->r;
226}
227
229{
230 return resource->info->pool;
231}
232
234{
235 return resource->info->pathname;
236}
237
239 const dav_resource *resource,
240 const char **dirpath_p,
241 const char **fname_p)
242{
244
245 if (resource->collection) {
247 if (fname_p != NULL)
248 *fname_p = NULL;
249 }
250 else {
251 const char *testpath, *rootpath;
252 char *dirpath = ap_make_dirstr_parent(ctx->pool, ctx->pathname);
253 apr_size_t dirlen = strlen(dirpath);
255
257 if (dirlen > 0) {
258 rv = apr_filepath_root(&rootpath, &testpath, 0, ctx->pool);
259 }
260
261 /* remove trailing slash from dirpath, unless it's a root path
262 */
263 if ((rv == APR_SUCCESS && testpath && *testpath)
264 || rv == APR_ERELATIVE) {
265 if (dirpath[dirlen - 1] == '/') {
266 dirpath[dirlen - 1] = '\0';
267 }
268 }
269
270 /* ###: Looks like a response could be appropriate
271 *
272 * APR_SUCCESS here tells us the dir is a root
273 * APR_ERELATIVE told us we had no root (ok)
274 * APR_EINCOMPLETE an incomplete testpath told us
275 * there was no -file- name here!
276 * APR_EBADPATH or other errors tell us this file
277 * path is undecipherable
278 */
279
280 if (rv == APR_SUCCESS || rv == APR_ERELATIVE) {
282 if (fname_p != NULL)
283 *fname_p = ctx->pathname + dirlen;
284 }
285 else {
286 return dav_new_error(ctx->pool, HTTP_INTERNAL_SERVER_ERROR, 0, rv,
287 "An incomplete/bad path was found in "
288 "dav_fs_dir_file_name.");
289 }
290 }
291
292 return NULL;
293}
294
295/* Note: picked up from ap_gm_timestr_822() */
296/* NOTE: buf must be at least DAV_TIMEBUF_SIZE chars in size */
298{
300
301 /* ### what to do if fails? */
302 (void) apr_time_exp_gmt(&tms, sec);
303
304 if (style == DAV_STYLE_ISO8601) {
305 /* ### should we use "-00:00" instead of "Z" ?? */
306
307 /* 20 chars plus null term */
308 apr_snprintf(buf, buflen, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2dZ",
309 tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
310 tms.tm_hour, tms.tm_min, tms.tm_sec);
311 return;
312 }
313
314 /* RFC 822 date format; as strftime '%a, %d %b %Y %T GMT' */
315
316 /* 29 chars plus null term */
317 apr_snprintf(buf, buflen, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT",
318 apr_day_snames[tms.tm_wday],
319 tms.tm_mday, apr_month_snames[tms.tm_mon],
320 tms.tm_year + 1900,
321 tms.tm_hour, tms.tm_min, tms.tm_sec);
322}
323
324/* Copy or move src to dst; src_finfo is used to propagate permissions
325 * bits across if non-NULL; dst_finfo must be non-NULL iff dst already
326 * exists. */
328 int is_move,
329 apr_pool_t * p,
330 const char *src,
331 const char *dst,
332 const apr_finfo_t *src_finfo,
333 const apr_finfo_t *dst_finfo,
335{
336 dav_buffer work_buf = { 0 };
341
342 if (pbuf == NULL)
343 pbuf = &work_buf;
344
345 /* Determine permissions to use for destination */
346 if (src_finfo && src_finfo->valid & APR_FINFO_PROT
347 && src_finfo->protection & APR_UEXECUTE) {
348 perms = src_finfo->protection;
349
350 if (dst_finfo != NULL) {
351 /* chmod it if it already exist */
354 "Could not set permissions on destination");
355 }
356 }
357 }
358 else {
360 }
361
363
366 /* ### use something besides 500? */
368 "Could not open file for reading");
369 }
370
371 /* ### do we need to deal with the umask? */
373 | APR_BINARY, perms, p);
374 if (status != APR_SUCCESS) {
376
378 "Could not open file for writing");
379 }
380
381 while (1) {
383
384 status = apr_file_read(inf, pbuf->buf, &len);
385 if (status != APR_SUCCESS && status != APR_EOF) {
387
390
392 /* ### ACK! Inconsistent state... */
393
394 /* ### use something besides 500? */
397 "Could not delete output after read "
398 "failure. Server is now in an "
399 "inconsistent state.");
400 }
401
402 /* ### use something besides 500? */
404 "Could not read input file");
405 }
406
407 if (status == APR_EOF)
408 break;
409
410 /* write any bytes that were read */
412 if (status != APR_SUCCESS) {
414
417
419 /* ### ACK! Inconsistent state... */
420
421 /* ### use something besides 500? */
424 "Could not delete output after write "
425 "failure. Server is now in an "
426 "inconsistent state.");
427 }
428
430 "Could not write output file");
431 }
432 }
433
436
437 if (is_move && (status = apr_file_remove(src, p)) != APR_SUCCESS) {
438 dav_error *err;
440
442 /*
443 * Something is wrong here but the result is what we wanted.
444 * We definitely should not remove the destination file.
445 */
447 apr_psprintf(p, "Could not remove source "
448 "file %s after move to %s. The "
449 "server may be in an "
450 "inconsistent state.", src, dst));
451 return err;
452 }
453 else if ((lcl_status = apr_file_remove(dst, p)) != APR_SUCCESS) {
454 /* ### ACK. this creates an inconsistency. do more!? */
455
456 /* ### use something besides 500? */
458 "Could not remove source or destination "
459 "file. Server is now in an inconsistent "
460 "state.");
461 }
462
463 /* ### use something besides 500? */
465 "Could not remove source file after move. "
466 "Destination was removed to ensure consistency.");
467 return err;
468 }
469
470 return NULL;
471}
472
473/* copy/move a file from within a state dir to another state dir */
474/* ### need more buffers to replace the pool argument */
476 int is_move,
477 apr_pool_t * p,
478 const char *src_dir, const char *src_file,
479 const char *dst_dir, const char *dst_file,
481{
482 apr_finfo_t src_finfo; /* finfo for source file */
483 apr_finfo_t dst_state_finfo; /* finfo for STATE directory */
484 apr_status_t rv;
485 const char *src;
486 const char *dst;
487
488 /* build the propset pathname for the source file */
490
491 /* the source file doesn't exist */
493 if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
494 return NULL;
495 }
496
497 /* build the pathname for the destination state dir */
499
500 /* ### do we need to deal with the umask? */
501
502 /* ensure that it exists */
504 if (rv != APR_SUCCESS) {
505 if (!APR_STATUS_IS_EEXIST(rv)) {
506 /* ### use something besides 500? */
508 "Could not create internal state directory");
509 }
510 }
511
512 /* get info about the state directory */
514 if (rv != APR_SUCCESS && rv != APR_INCOMPLETE) {
515 /* Ack! Where'd it go? */
516 /* ### use something besides 500? */
518 "State directory disappeared");
519 }
520
521 /* The mkdir() may have failed because a *file* exists there already */
522 if (dst_state_finfo.filetype != APR_DIR) {
523 /* ### try to recover by deleting this file? (and mkdir again) */
524 /* ### use something besides 500? */
526 "State directory is actually a file");
527 }
528
529 /* append the target file to the state directory pathname */
530 dst = apr_pstrcat(p, dst, "/", dst_file, NULL);
531
532 /* copy/move the file now */
533 if (is_move) {
534 /* try simple rename first */
535 rv = apr_file_rename(src, dst, p);
536 if (APR_STATUS_IS_EXDEV(rv)) {
537 return dav_fs_copymove_file(is_move, p, src, dst, NULL, NULL, pbuf);
538 }
539 if (rv != APR_SUCCESS) {
540 /* ### use something besides 500? */
542 "Could not move state file.");
543 }
544 }
545 else
546 {
547 /* gotta copy (and delete) */
548 return dav_fs_copymove_file(is_move, p, src, dst, NULL, NULL, pbuf);
549 }
550
551 return NULL;
552}
553
555 const dav_resource *src,
556 const dav_resource *dst,
558{
559 const char *src_dir;
560 const char *src_file;
561 const char *src_state1;
562 const char *src_state2;
563 const char *dst_dir;
564 const char *dst_file;
565 const char *dst_state1;
566 const char *dst_state2;
567 dav_error *err;
568
569 /* Get directory and filename for resources */
570 /* ### should test these result values... */
573
574 /* Get the corresponding state files for each resource */
577#if DAV_DEBUG
578 if ((src_state2 != NULL && dst_state2 == NULL) ||
579 (src_state2 == NULL && dst_state2 != NULL)) {
581 "DESIGN ERROR: dav_dbm_get_statefiles() "
582 "returned inconsistent results.");
583 }
584#endif
585
586 err = dav_fs_copymove_state(is_move, p,
589 pbuf);
590
591 if (err == NULL && src_state2 != NULL) {
592 err = dav_fs_copymove_state(is_move, p,
595 pbuf);
596
597 if (err != NULL) {
598 /* ### CRAP. inconsistency. */
599 /* ### should perform some cleanup at the target if we still
600 ### have the original files */
601
602 /* Change the error to reflect the bad server state. */
604 err->desc =
605 "Could not fully copy/move the properties. "
606 "The server is now in an inconsistent state.";
607 }
608 }
609
610 return err;
611}
612
614{
615 const char *dirpath;
616 const char *fname;
617 const char *state1;
618 const char *state2;
619 const char *pathname;
621
622 /* Get directory, filename, and state-file names for the resource */
623 /* ### should test this result value... */
626
627 /* build the propset pathname for the file */
629 dirpath,
630 "/" DAV_FS_STATE_DIR "/",
631 state1,
632 NULL);
633
634 /* note: we may get ENOENT if the state dir is not present */
638 "Could not remove properties.");
639 }
640
641 if (state2 != NULL) {
642 /* build the propset pathname for the file */
644 dirpath,
645 "/" DAV_FS_STATE_DIR "/",
646 state2,
647 NULL);
648
651 /* ### CRAP. only removed half. */
653 "Could not fully remove properties. "
654 "The server is now in an inconsistent "
655 "state.");
656 }
657 }
658
659 return NULL;
660}
661
662/* --------------------------------------------------------------------
663**
664** REPOSITORY HOOK FUNCTIONS
665*/
666
668 request_rec *r,
669 const char *root_dir,
670 const char *label,
671 int use_checked_in,
673{
676 char *s;
677 char *filename;
679
680 /* ### optimize this into a single allocation! */
681
682 /* Create private resource context descriptor */
683 ctx = apr_pcalloc(r->pool, sizeof(*ctx));
684 ctx->finfo = r->finfo;
685 ctx->r = r;
686
687 /* ### this should go away */
688 ctx->pool = r->pool;
689
690 /* Preserve case on OSes which fold canonical filenames */
691#if 0
692 /* ### not available in Apache 2.0 yet */
693 filename = r->case_preserved_filename;
694#else
696#endif
697
698 /*
699 ** If there is anything in the path_info, then this indicates that the
700 ** entire path was not used to specify the file/dir. We want to append
701 ** it onto the filename so that we get a "valid" pathname for null
702 ** resources.
703 */
705
706 /* make sure the pathname does not have a trailing "/" */
707 len = strlen(s);
708 if (len > 1 && s[len - 1] == '/') {
709 s[len - 1] = '\0';
710 }
711 ctx->pathname = s;
712
713 /* Create resource descriptor */
714 resource = apr_pcalloc(r->pool, sizeof(*resource));
716 resource->info = ctx;
718 resource->pool = r->pool;
719
720 /* make sure the URI does not have a trailing "/" */
721 len = strlen(r->uri);
722 if (len > 1 && r->uri[len - 1] == '/') {
723 s = apr_pstrmemdup(r->pool, r->uri, len-1);
724 resource->uri = s;
725 }
726 else {
727 resource->uri = r->uri;
728 }
729
730 if (r->finfo.filetype != APR_NOFILE) {
731 resource->exists = 1;
732 resource->collection = r->finfo.filetype == APR_DIR;
733
734 /* unused info in the URL will indicate a null resource */
735
736 if (r->path_info != NULL && *r->path_info != '\0') {
737 if (resource->collection) {
738 /* only a trailing "/" is allowed */
739 if (*r->path_info != '/' || r->path_info[1] != '\0') {
740
741 /*
742 ** This URL/filename represents a locknull resource or
743 ** possibly a destination of a MOVE/COPY
744 */
745 resource->exists = 0;
746 resource->collection = 0;
747 }
748 }
749 else
750 {
751 /*
752 ** The base of the path refers to a file -- nothing should
753 ** be in path_info. The resource is simply an error: it
754 ** can't be a null or a locknull resource.
755 */
756 return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, 0,
757 "The URL contains extraneous path "
758 "components. The resource could not "
759 "be identified.");
760 }
761
762 /* retain proper integrity across the structures */
763 if (!resource->exists) {
764 ctx->finfo.filetype = APR_NOFILE;
765 }
766 }
767 }
768
770 return NULL;
771}
772
775{
778 dav_resource *parent_resource;
779 apr_status_t rv;
780 char *dirpath;
781 const char *testroot;
782 const char *testpath;
783
784 /* If we're at the root of the URL space, then there is no parent. */
785 if (strcmp(resource->uri, "/") == 0) {
787 return NULL;
788 }
789
790 /* If given resource is root, then there is no parent.
791 * Unless we can retrieve the filepath root, this is
792 * intendend to fail. If we split the root and
793 * no path info remains, then we also fail.
794 */
795 testpath = ctx->pathname;
796 rv = apr_filepath_root(&testroot, &testpath, 0, ctx->pool);
797 if ((rv != APR_SUCCESS && rv != APR_ERELATIVE)
798 || !testpath || !*testpath) {
800 return NULL;
801 }
802
803 /* ### optimize this into a single allocation! */
804
805 /* Create private resource context descriptor */
806 parent_ctx = apr_pcalloc(ctx->pool, sizeof(*parent_ctx));
807
808 /* ### this should go away */
809 parent_ctx->pool = ctx->pool;
810
811 dirpath = ap_make_dirstr_parent(ctx->pool, ctx->pathname);
812 if (strlen(dirpath) > 1 && dirpath[strlen(dirpath) - 1] == '/')
813 dirpath[strlen(dirpath) - 1] = '\0';
814 parent_ctx->pathname = dirpath;
815
816 parent_resource = apr_pcalloc(ctx->pool, sizeof(*parent_resource));
817 parent_resource->info = parent_ctx;
818 parent_resource->collection = 1;
819 parent_resource->hooks = &dav_hooks_repository_fs;
820 parent_resource->pool = resource->pool;
821
822 if (resource->uri != NULL) {
823 char *uri = ap_make_dirstr_parent(ctx->pool, resource->uri);
824 if (strlen(uri) > 1 && uri[strlen(uri) - 1] == '/')
825 uri[strlen(uri) - 1] = '\0';
826 parent_resource->uri = uri;
827 }
828
829 rv = apr_stat(&parent_ctx->finfo, parent_ctx->pathname,
830 APR_FINFO_NORM, ctx->pool);
831 if (rv == APR_SUCCESS || rv == APR_INCOMPLETE) {
832 parent_resource->exists = 1;
833 }
834
835 *result_parent = parent_resource;
836 return NULL;
837}
838
840 const dav_resource *res1,
841 const dav_resource *res2)
842{
845
846 if (res1->hooks != res2->hooks)
847 return 0;
848
849 if ((ctx1->finfo.filetype != APR_NOFILE) && (ctx2->finfo.filetype != APR_NOFILE)
850 && (ctx1->finfo.valid & ctx2->finfo.valid & APR_FINFO_INODE)) {
851 return ctx1->finfo.inode == ctx2->finfo.inode;
852 }
853 else {
854 return strcmp(ctx1->pathname, ctx2->pathname) == 0;
855 }
856}
857
859 const dav_resource *res1,
860 const dav_resource *res2)
861{
864 apr_size_t len1 = strlen(ctx1->pathname);
866
867 if (res1->hooks != res2->hooks)
868 return 0;
869
870 /* it is safe to use ctx2 now */
871 len2 = strlen(ctx2->pathname);
872
873 return (len2 > len1
874 && memcmp(ctx1->pathname, ctx2->pathname, len1) == 0
875 && ctx2->pathname[len1] == '/');
876}
877
879{
880 dav_stream *ds = data;
881 if (ds->temppath) {
882 apr_file_remove(ds->temppath, ds->p);
883 }
884 return APR_SUCCESS;
885}
886
887/* custom mktemp that creates the file with APR_OS_DEFAULT permissions */
889{
890 apr_status_t rv;
891 int num = ((getpid() << 7) + (apr_uintptr_t)templ % (1 << 16) ) %
892 ( 1 << 23 ) ;
893 char *numstr = templ + strlen(templ) - 6;
894
896
897 do {
898 num = (num + 1) % ( 1 << 23 );
899 apr_snprintf(numstr, 7, "%06x", num);
900 rv = apr_file_open(fp, templ,
903 } while (APR_STATUS_IS_EEXIST(rv));
904
905 return rv;
906}
907
910 dav_stream **stream)
911{
912 apr_pool_t *p = resource->info->pool;
913 dav_stream *ds = apr_pcalloc(p, sizeof(*ds));
915 apr_status_t rv;
916
917 switch (mode) {
918 default:
920 break;
921
924 break;
927 break;
928 }
929
930 ds->p = p;
931 ds->pathname = resource->info->pathname;
932 ds->temppath = NULL;
933 ds->unlink_on_error = 0;
934
935 if (mode == DAV_MODE_WRITE_TRUNC) {
936 ds->temppath = apr_pstrcat(p, ap_make_dirstr_parent(p, ds->pathname),
937 DAV_FS_TMP_PREFIX "XXXXXX", NULL);
938 rv = dav_fs_mktemp(&ds->f, ds->temppath, ds->p);
941 }
942 else if (mode == DAV_MODE_WRITE_SEEKABLE) {
943 rv = apr_file_open(&ds->f, ds->pathname, flags | APR_FOPEN_EXCL,
944 APR_OS_DEFAULT, ds->p);
945 if (rv == APR_SUCCESS) {
946 /* we have created a new file */
947 ds->unlink_on_error = 1;
948 }
949 else if (APR_STATUS_IS_EEXIST(rv)) {
950 rv = apr_file_open(&ds->f, ds->pathname, flags, APR_OS_DEFAULT,
951 ds->p);
952 if (rv != APR_SUCCESS) {
953 return dav_new_error(p, MAP_IO2HTTP(rv), 0, rv,
954 apr_psprintf(p, "Could not open an existing "
955 "resource for writing: %s.",
956 ds->pathname));
957 }
958 }
959 }
960 else {
961 rv = apr_file_open(&ds->f, ds->pathname, flags, APR_OS_DEFAULT, ds->p);
962 if (rv != APR_SUCCESS) {
963 return dav_new_error(p, MAP_IO2HTTP(rv), 0, rv,
964 apr_psprintf(p, "Could not open an existing "
965 "resource for reading: %s.",
966 ds->pathname));
967 }
968 }
969
970 if (rv != APR_SUCCESS) {
971 return dav_new_error(p, MAP_IO2HTTP(rv), 0, rv,
972 apr_psprintf(p, "An error occurred while opening "
973 "a resource for writing: %s.",
974 ds->pathname));
975 }
976
977 /* (APR registers cleanups for the fd with the pool) */
978
979 *stream = ds;
980 return NULL;
981}
982
984{
985 apr_status_t rv;
986
987 apr_file_close(stream->f);
988
989 if (!commit) {
990 if (stream->temppath) {
991 apr_pool_cleanup_run(stream->p, stream, tmpfile_cleanup);
992 }
993 else if (stream->unlink_on_error) {
994 if ((rv = apr_file_remove(stream->pathname, stream->p))
995 != APR_SUCCESS) {
996 /* ### use a better description? */
997 return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0,
998 rv,
999 "There was a problem removing (rolling "
1000 "back) the resource "
1001 "when it was being closed.");
1002 }
1003 }
1004 }
1005 else if (stream->temppath) {
1006 rv = apr_file_rename(stream->temppath, stream->pathname, stream->p);
1007 if (rv) {
1008 return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, rv,
1009 "There was a problem writing the file "
1010 "atomically after writes.");
1011 }
1012 apr_pool_cleanup_kill(stream->p, stream, tmpfile_cleanup);
1013 }
1014
1015 return NULL;
1016}
1017
1019 const void *buf, apr_size_t bufsize)
1020{
1022
1025 return dav_new_error(stream->p, HTTP_INSUFFICIENT_STORAGE, 0, status,
1026 "There is not enough storage to write to "
1027 "this resource.");
1028 }
1029 else if (status != APR_SUCCESS) {
1030 /* ### use something besides 500? */
1032 "An error occurred while writing to a "
1033 "resource.");
1034 }
1035 return NULL;
1036}
1037
1039{
1041
1042 if ((status = apr_file_seek(stream->f, APR_SET, &abs_pos))
1043 != APR_SUCCESS) {
1044 /* ### should check whether apr_file_seek set abs_pos was set to the
1045 * correct position? */
1046 /* ### use something besides 500? */
1048 "Could not seek to specified position in the "
1049 "resource.");
1050 }
1051 return NULL;
1052}
1053
1054
1055#if DEBUG_GET_HANDLER
1056
1057/* only define set_headers() and deliver() for debug purposes */
1058
1059
1061 const dav_resource *resource)
1062{
1063 /* ### this function isn't really used since we have a get_pathname */
1064 if (!resource->exists)
1065 return NULL;
1066
1067 /* make sure the proper mtime is in the request record */
1069
1070 /* ### note that these use r->filename rather than <resource> */
1072 ap_set_etag(r);
1073
1074 /* we accept byte-ranges */
1076
1077 /* set up the Content-Length header */
1079
1080 /* ### how to set the content type? */
1081 /* ### until this is resolved, the Content-Type header is busted */
1082
1083 return NULL;
1084}
1085
1087 ap_filter_t *output)
1088{
1089 apr_pool_t *pool = resource->pool;
1091 apr_file_t *fd;
1093 apr_bucket *bkt;
1094
1095 /* Check resource type */
1098 && resource->type != DAV_RESOURCE_TYPE_WORKING) {
1099 return dav_new_error(pool, HTTP_CONFLICT, 0, 0,
1100 "Cannot GET this type of resource.");
1101 }
1102 if (resource->collection) {
1103 return dav_new_error(pool, HTTP_CONFLICT, 0, 0,
1104 "There is no default response to GET for a "
1105 "collection.");
1106 }
1107
1108 if ((status = apr_file_open(&fd, resource->info->pathname,
1109 APR_READ | APR_BINARY, 0,
1110 pool)) != APR_SUCCESS) {
1112 "File permissions deny server access.");
1113 }
1114
1115 bb = apr_brigade_create(pool, output->c->bucket_alloc);
1116
1118
1121
1122 if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) {
1124 "Could not write contents to filter.");
1125 }
1126
1127 return NULL;
1128}
1129
1130#endif /* DEBUG_GET_HANDLER */
1131
1132
1134{
1137
1138 status = apr_dir_make(ctx->pathname, APR_OS_DEFAULT, ctx->pool);
1141 "There is not enough storage to create "
1142 "this collection.");
1143 }
1144 else if (APR_STATUS_IS_ENOENT(status)) {
1145 return dav_new_error(ctx->pool, HTTP_CONFLICT, 0, status,
1146 "Cannot create collection; intermediate "
1147 "collection does not exist.");
1148 }
1149 else if (status != APR_SUCCESS) {
1150 /* ### refine this error message? */
1151 return dav_new_error(ctx->pool, HTTP_FORBIDDEN, 0, status,
1152 "Unable to create collection.");
1153 }
1154
1155 /* update resource state to show it exists as a collection */
1156 resource->exists = 1;
1157 resource->collection = 1;
1158
1159 return NULL;
1160}
1161
1163 int calltype)
1164{
1168 dav_resource_private *dstinfo = ctx->res_dst->info;
1169 dav_error *err = NULL;
1170
1171 if (wres->resource->collection) {
1173 /* Postfix call for MOVE. delete the source dir.
1174 * Note: when copying, we do not enable the postfix-traversal.
1175 */
1176 /* ### we are ignoring any error here; what should we do? */
1177 (void) apr_dir_remove(srcinfo->pathname, ctx->pool);
1178 }
1179 else {
1180 /* copy/move of a collection. Create the new, target collection */
1181 if ((status = apr_dir_make(dstinfo->pathname, APR_OS_DEFAULT,
1182 ctx->pool)) != APR_SUCCESS) {
1183 /* ### assume it was a permissions problem */
1184 /* ### need a description here */
1186 }
1187 }
1188 }
1189 else {
1190 err = dav_fs_copymove_file(ctx->is_move, ctx->pool,
1191 srcinfo->pathname, dstinfo->pathname,
1192 &srcinfo->finfo,
1193 ctx->res_dst->exists ? &dstinfo->finfo : NULL,
1194 &ctx->work_buf);
1195 /* ### push a higher-level description? */
1196 }
1197
1198 /*
1199 ** If we have a "not so bad" error, then it might need to go into a
1200 ** multistatus response.
1201 **
1202 ** For a MOVE, it will always go into the multistatus. It could be
1203 ** that everything has been moved *except* for the root. Using a
1204 ** multistatus (with no errors for the other resources) will signify
1205 ** this condition.
1206 **
1207 ** For a COPY, we are traversing in a prefix fashion. If the root fails,
1208 ** then we can just bail out now.
1209 */
1210 if (err != NULL
1211 && !ap_is_HTTP_SERVER_ERROR(err->status)
1212 && (ctx->is_move
1213 || !dav_fs_is_same_resource(wres->resource, ctx->root))) {
1214 /* ### use errno to generate DAV:responsedescription? */
1215 dav_add_response(wres, err->status, NULL);
1216
1217 /* the error is in the multistatus now. do not stop the traversal. */
1218 return NULL;
1219 }
1220
1221 return err;
1222}
1223
1225 int is_move,
1226 const dav_resource *src,
1227 const dav_resource *dst,
1228 int depth,
1229 dav_response **response)
1230{
1231 dav_error *err = NULL;
1232 dav_buffer work_buf = { 0 };
1233
1234 *response = NULL;
1235
1236 /* if a collection, recursively copy/move it and its children,
1237 * including the state dirs
1238 */
1239 if (src->collection) {
1240 dav_walk_params params = { 0 };
1242
1245 params.pool = src->info->pool;
1246 params.root = src;
1247
1248 /* params.walk_ctx is managed by dav_fs_internal_walk() */
1249
1250 /* postfix is needed for MOVE to delete source dirs */
1251 if (is_move)
1252 params.walk_type |= DAV_WALKTYPE_POSTFIX;
1253
1254 /* note that we return the error OR the multistatus. never both */
1255
1256 if ((err = dav_fs_internal_walk(&params, depth, is_move, dst,
1257 &multi_status)) != NULL) {
1258 /* on a "real" error, then just punt. nothing else to do. */
1259 return err;
1260 }
1261
1262 if ((*response = multi_status) != NULL) {
1263 /* some multistatus responses exist. wrap them in a 207 */
1264 return dav_new_error(src->info->pool, HTTP_MULTI_STATUS, 0, 0,
1265 "Error(s) occurred on some resources during "
1266 "the COPY/MOVE process.");
1267 }
1268
1269 return NULL;
1270 }
1271
1272 /* not a collection */
1273 if ((err = dav_fs_copymove_file(is_move, src->info->pool,
1274 src->info->pathname, dst->info->pathname,
1275 &src->info->finfo,
1276 dst->exists ? &dst->info->finfo : NULL,
1277 &work_buf)) != NULL) {
1278 /* ### push a higher-level description? */
1279 return err;
1280 }
1281
1282 /* copy/move properties as well */
1283 return dav_fs_copymoveset(is_move, src->info->pool, src, dst, &work_buf);
1284}
1285
1287 const dav_resource *src,
1289 int depth,
1290 dav_response **response)
1291{
1292 dav_error *err;
1293
1294#if DAV_DEBUG
1295 if (src->hooks != dst->hooks) {
1296 /*
1297 ** ### strictly speaking, this is a design error; we should not
1298 ** ### have reached this point.
1299 */
1300 return dav_new_error(src->info->pool, HTTP_INTERNAL_SERVER_ERROR, 0, 0,
1301 "DESIGN ERROR: a mix of repositories "
1302 "was passed to copy_resource.");
1303 }
1304#endif
1305
1306 if ((err = dav_fs_copymove_resource(0, src, dst, depth,
1307 response)) == NULL) {
1308
1309 /* update state of destination resource to show it exists */
1310 dst->exists = 1;
1311 dst->collection = src->collection;
1312 }
1313
1314 return err;
1315}
1316
1320 dav_response **response)
1321{
1324 dav_error *err;
1325 apr_status_t rv;
1326
1327#if DAV_DEBUG
1328 if (src->hooks != dst->hooks) {
1329 /*
1330 ** ### strictly speaking, this is a design error; we should not
1331 ** ### have reached this point.
1332 */
1333 return dav_new_error(src->info->pool, HTTP_INTERNAL_SERVER_ERROR, 0, 0,
1334 "DESIGN ERROR: a mix of repositories "
1335 "was passed to move_resource.");
1336 }
1337#endif
1338
1339
1340 /* try rename first */
1341 rv = apr_file_rename(srcinfo->pathname, dstinfo->pathname, srcinfo->pool);
1342
1343 /* if we can't simply rename, then do it the hard way... */
1344 if (APR_STATUS_IS_EXDEV(rv)) {
1346 response)) == NULL) {
1347 /* update resource states */
1348 dst->exists = 1;
1349 dst->collection = src->collection;
1350 src->exists = 0;
1351 src->collection = 0;
1352 }
1353
1354 return err;
1355 }
1356
1357 /* no multistatus response */
1358 *response = NULL;
1359
1360 if (rv != APR_SUCCESS) {
1361 /* ### should have a better error than this. */
1363 "Could not rename resource.");
1364 }
1365
1366 /* Rename did work. Update resource states and move properties as well */
1367 dst->exists = 1;
1368 dst->collection = src->collection;
1369 src->exists = 0;
1370 src->collection = 0;
1371
1372 if ((err = dav_fs_copymoveset(1, src->info->pool,
1373 src, dst, NULL)) == NULL) {
1374 /* no error. we're done. go ahead and return now. */
1375 return NULL;
1376 }
1377
1378 /* error occurred during properties move; try to put resource back */
1379 if (apr_file_rename(dstinfo->pathname, srcinfo->pathname,
1380 srcinfo->pool) != APR_SUCCESS) {
1381 /* couldn't put it back! */
1382 return dav_push_error(srcinfo->pool,
1384 "The resource was moved, but a failure "
1385 "occurred during the move of its "
1386 "properties. The resource could not be "
1387 "restored to its original location. The "
1388 "server is now in an inconsistent state.",
1389 err);
1390 }
1391
1392 /* update resource states again */
1393 src->exists = 1;
1394 src->collection = dst->collection;
1395 dst->exists = 0;
1396 dst->collection = 0;
1397
1398 /* resource moved back, but properties may be inconsistent */
1399 return dav_push_error(srcinfo->pool,
1401 "The resource was moved, but a failure "
1402 "occurred during the move of its properties. "
1403 "The resource was moved back to its original "
1404 "location, but its properties may have been "
1405 "partially moved. The server may be in an "
1406 "inconsistent state.",
1407 err);
1408}
1409
1411{
1413
1414 /* do not attempt to remove a null resource,
1415 * or a collection with children
1416 */
1417 if (wres->resource->exists &&
1419 /* try to remove the resource */
1421
1422 result = wres->resource->collection
1423 ? apr_dir_remove(info->pathname, wres->pool)
1424 : apr_file_remove(info->pathname, wres->pool);
1425
1426 /*
1427 ** If an error occurred, then add it to multistatus response.
1428 ** Note that we add it for the root resource, too. It is quite
1429 ** possible to delete the whole darn tree, yet fail on the root.
1430 **
1431 ** (also: remember we are deleting via a postfix traversal)
1432 */
1433 if (result != APR_SUCCESS) {
1434 /* ### assume there is a permissions problem */
1435
1436 /* ### use errno to generate DAV:responsedescription? */
1438 }
1439 }
1440
1441 return NULL;
1442}
1443
1445 dav_response **response)
1446{
1449
1450 *response = NULL;
1451
1452 /* if a collection, recursively remove it and its children,
1453 * including the state dirs
1454 */
1455 if (resource->collection) {
1456 dav_walk_params params = { 0 };
1457 dav_error *err = NULL;
1459
1460 params.walk_type = (DAV_WALKTYPE_NORMAL
1464 params.pool = info->pool;
1465 params.root = resource;
1466
1468 &multi_status)) != NULL) {
1469 /* on a "real" error, then just punt. nothing else to do. */
1470 return err;
1471 }
1472
1473 if ((*response = multi_status) != NULL) {
1474 /* some multistatus responses exist. wrap them in a 207 */
1475 return dav_new_error(info->pool, HTTP_MULTI_STATUS, 0, 0,
1476 "Error(s) occurred on some resources during "
1477 "the deletion process.");
1478 }
1479
1480 /* no errors... update resource state */
1481 resource->exists = 0;
1482 resource->collection = 0;
1483
1484 return NULL;
1485 }
1486
1487 /* not a collection; remove the file and its properties */
1488 if ((status = apr_file_remove(info->pathname, info->pool)) != APR_SUCCESS) {
1489 /* ### put a description in here */
1490 return dav_new_error(info->pool, HTTP_FORBIDDEN, 0, status, NULL);
1491 }
1492
1493 /* update resource state */
1494 resource->exists = 0;
1495 resource->collection = 0;
1496
1497 /* remove properties and return its result */
1498 return dav_fs_deleteset(info->pool, resource);
1499}
1500
1501/* ### move this to dav_util? */
1502/* Walk recursively down through directories, *
1503 * including lock-null resources as we go. */
1505{
1506 const dav_walk_params *params = fsctx->params;
1507 apr_pool_t *pool = params->pool;
1509 dav_error *err = NULL;
1510 int isdir = fsctx->res1.collection;
1512 apr_dir_t *dirp;
1513
1514 /* ensure the context is prepared properly, then call the func */
1515 err = (*params->func)(&fsctx->wres,
1516 isdir
1519 if (err != NULL) {
1520 return err;
1521 }
1522
1523 if (depth == 0 || !isdir) {
1524 return NULL;
1525 }
1526
1527 /* put a trailing slash onto the directory, in preparation for appending
1528 * files to it as we discovery them within the directory */
1530 fsctx->path1.buf[fsctx->path1.cur_len++] = '/';
1531 fsctx->path1.buf[fsctx->path1.cur_len] = '\0'; /* in pad area */
1532
1533 /* if a secondary path is present, then do that, too */
1534 if (fsctx->path2.buf != NULL) {
1536 fsctx->path2.buf[fsctx->path2.cur_len++] = '/';
1537 fsctx->path2.buf[fsctx->path2.cur_len] = '\0'; /* in pad area */
1538 }
1539
1540 /* Note: the URI should ALREADY have a trailing "/" */
1541
1542 /* for this first pass of files, all resources exist */
1543 fsctx->res1.exists = 1;
1544
1545 /* a file is the default; we'll adjust if we hit a directory */
1546 fsctx->res1.collection = 0;
1547 fsctx->res2.collection = 0;
1548
1549 /* open and scan the directory */
1550 if ((status = apr_dir_open(&dirp, fsctx->path1.buf, pool)) != APR_SUCCESS) {
1551 /* ### need a better error */
1553 }
1556
1557 len = strlen(dirent.name);
1558
1559 /* avoid recursing into our current, parent, or state directories */
1560 if (dirent.name[0] == '.'
1561 && (len == 1 || (dirent.name[1] == '.' && len == 2))) {
1562 continue;
1563 }
1564
1565 if (params->walk_type & DAV_WALKTYPE_AUTH) {
1566 /* ### need to authorize each file */
1567 /* ### example: .htaccess is normally configured to fail auth */
1568
1569 /* stuff in the state directory and temp files are never authorized! */
1570 if (!strcmp(dirent.name, DAV_FS_STATE_DIR) ||
1572 strlen(DAV_FS_TMP_PREFIX))) {
1573 continue;
1574 }
1575 }
1576 /* skip the state dir and temp files unless a HIDDEN is performed */
1577 if (!(params->walk_type & DAV_WALKTYPE_HIDDEN)
1578 && (!strcmp(dirent.name, DAV_FS_STATE_DIR) ||
1580 strlen(DAV_FS_TMP_PREFIX)))) {
1581 continue;
1582 }
1583
1584 /* append this file onto the path buffer (copy null term) */
1585 dav_buffer_place_mem(pool, &fsctx->path1, dirent.name, len + 1, 0);
1586
1587 status = apr_stat(&fsctx->info1.finfo, fsctx->path1.buf,
1589 if (status != APR_SUCCESS && status != APR_INCOMPLETE) {
1590 dav_resource_private *ctx = params->root->info;
1591
1593 APLOGNO(10472) "could not access file (%s) during directory walk",
1594 fsctx->path1.buf);
1595
1596 /* If being tolerant, ignore failure due to losing a race
1597 * with some other process deleting files out from under
1598 * the directory walk. */
1599 if ((params->walk_type & DAV_WALKTYPE_TOLERANT)
1601 continue;
1602 }
1603 /* woah! where'd it go? */
1604 /* ### should have a better error here */
1606 break;
1607 }
1608
1609 /* copy the file to the URI, too. NOTE: we will pad an extra byte
1610 for the trailing slash later. */
1611 dav_buffer_place_mem(pool, &fsctx->uri_buf, dirent.name, len + 1, 1);
1612
1613 /* if there is a secondary path, then do that, too */
1614 if (fsctx->path2.buf != NULL) {
1615 dav_buffer_place_mem(pool, &fsctx->path2, dirent.name, len + 1, 0);
1616 }
1617
1618 /* set up the (internal) pathnames for the two resources */
1619 fsctx->info1.pathname = fsctx->path1.buf;
1620 fsctx->info2.pathname = fsctx->path2.buf;
1621
1622 /* set up the URI for the current resource */
1623 fsctx->res1.uri = fsctx->uri_buf.buf;
1624
1625 /* ### for now, only process regular files (e.g. skip symlinks) */
1626 if (fsctx->info1.finfo.filetype == APR_REG) {
1627 /* call the function for the specified dir + file */
1628 if ((err = (*params->func)(&fsctx->wres,
1630 /* ### maybe add a higher-level description? */
1631 break;
1632 }
1633 }
1634 else if (fsctx->info1.finfo.filetype == APR_DIR) {
1635 apr_size_t save_path_len = fsctx->path1.cur_len;
1636 apr_size_t save_uri_len = fsctx->uri_buf.cur_len;
1637 apr_size_t save_path2_len = fsctx->path2.cur_len;
1638
1639 /* adjust length to incorporate the subdir name */
1640 fsctx->path1.cur_len += len;
1641 fsctx->path2.cur_len += len;
1642
1643 /* adjust URI length to incorporate subdir and a slash */
1644 fsctx->uri_buf.cur_len += len + 1;
1645 fsctx->uri_buf.buf[fsctx->uri_buf.cur_len - 1] = '/';
1646 fsctx->uri_buf.buf[fsctx->uri_buf.cur_len] = '\0';
1647
1648 /* switch over to a collection */
1649 fsctx->res1.collection = 1;
1650 fsctx->res2.collection = 1;
1651
1652 /* recurse on the subdir */
1653 /* ### don't always want to quit on error from single child */
1654 if ((err = dav_fs_walker(fsctx, depth - 1)) != NULL) {
1655 /* ### maybe add a higher-level description? */
1656 break;
1657 }
1658
1659 /* put the various information back */
1660 fsctx->path1.cur_len = save_path_len;
1661 fsctx->path2.cur_len = save_path2_len;
1662 fsctx->uri_buf.cur_len = save_uri_len;
1663
1664 fsctx->res1.collection = 0;
1665 fsctx->res2.collection = 0;
1666
1667 /* assert: res1.exists == 1 */
1668 }
1669 }
1670
1671 /* ### check the return value of this? */
1673
1674 if (err != NULL)
1675 return err;
1676
1677 if (params->walk_type & DAV_WALKTYPE_LOCKNULL) {
1678 apr_size_t offset = 0;
1679
1680 /* null terminate the directory name */
1681 fsctx->path1.buf[fsctx->path1.cur_len - 1] = '\0';
1682
1683 /* Include any lock null resources found in this collection */
1684 fsctx->res1.collection = 1;
1686 &fsctx->locknull_buf)) != NULL) {
1687 /* ### maybe add a higher-level description? */
1688 return err;
1689 }
1690
1691 /* put a slash back on the end of the directory */
1692 fsctx->path1.buf[fsctx->path1.cur_len - 1] = '/';
1693
1694 /* these are all non-existent (files) */
1695 fsctx->res1.exists = 0;
1696 fsctx->res1.collection = 0;
1697 memset(&fsctx->info1.finfo, 0, sizeof(fsctx->info1.finfo));
1698
1699 while (offset < fsctx->locknull_buf.cur_len) {
1700 apr_size_t len = strlen(fsctx->locknull_buf.buf + offset);
1701 dav_lock *locks = NULL;
1702
1703 /*
1704 ** Append the locknull file to the paths and the URI. Note that
1705 ** we don't have to pad the URI for a slash since a locknull
1706 ** resource is not a collection.
1707 */
1709 fsctx->locknull_buf.buf + offset, len + 1, 0);
1710 dav_buffer_place_mem(pool, &fsctx->uri_buf,
1711 fsctx->locknull_buf.buf + offset, len + 1, 0);
1712 if (fsctx->path2.buf != NULL) {
1714 fsctx->locknull_buf.buf + offset,
1715 len + 1, 0);
1716 }
1717
1718 /* set up the (internal) pathnames for the two resources */
1719 fsctx->info1.pathname = fsctx->path1.buf;
1720 fsctx->info2.pathname = fsctx->path2.buf;
1721
1722 /* set up the URI for the current resource */
1723 fsctx->res1.uri = fsctx->uri_buf.buf;
1724
1725 /*
1726 ** To prevent a PROPFIND showing an expired locknull
1727 ** resource, query the lock database to force removal
1728 ** of both the lock entry and .locknull, if necessary..
1729 ** Sure, the query in PROPFIND would do this.. after
1730 ** the locknull resource was already included in the
1731 ** return.
1732 **
1733 ** NOTE: we assume the caller has opened the lock database
1734 ** if they have provided DAV_WALKTYPE_LOCKNULL.
1735 */
1736 /* ### we should also look into opening it read-only and
1737 ### eliding timed-out items from the walk, yet leaving
1738 ### them in the locknull database until somebody opens
1739 ### the thing writable.
1740 */
1741 /* ### probably ought to use has_locks. note the problem
1742 ### mentioned above, though... we would traverse this as
1743 ### a locknull, but then a PROPFIND would load the lock
1744 ### info, causing a timeout and the locks would not be
1745 ### reported. Therefore, a null resource would be returned
1746 ### in the PROPFIND.
1747 ###
1748 ### alternative: just load unresolved locks. any direct
1749 ### locks will be timed out (correct). any indirect will
1750 ### not (correct; consider if a parent timed out -- the
1751 ### timeout routines do not walk and remove indirects;
1752 ### even the resolve func would probably fail when it
1753 ### tried to find a timed-out direct lock).
1754 */
1755 if ((err = dav_lock_query(params->lockdb, &fsctx->res1,
1756 &locks)) != NULL) {
1757 /* ### maybe add a higher-level description? */
1758 return err;
1759 }
1760
1761 /* call the function for the specified dir + file */
1762 if (locks != NULL &&
1763 (err = (*params->func)(&fsctx->wres,
1765 /* ### maybe add a higher-level description? */
1766 return err;
1767 }
1768
1769 offset += len + 1;
1770 }
1771
1772 /* reset the exists flag */
1773 fsctx->res1.exists = 1;
1774 }
1775
1776 if (params->walk_type & DAV_WALKTYPE_POSTFIX) {
1777 /* replace the dirs' trailing slashes with null terms */
1778 fsctx->path1.buf[--fsctx->path1.cur_len] = '\0';
1779 fsctx->uri_buf.buf[--fsctx->uri_buf.cur_len] = '\0';
1780 if (fsctx->path2.buf != NULL) {
1781 fsctx->path2.buf[--fsctx->path2.cur_len] = '\0';
1782 }
1783
1784 /* this is a collection which exists */
1785 fsctx->res1.collection = 1;
1786
1787 return (*params->func)(&fsctx->wres, DAV_CALLTYPE_POSTFIX);
1788 }
1789
1790 return NULL;
1791}
1792
1794 int depth, int is_move,
1795 const dav_resource *root_dst,
1796 dav_response **response)
1797{
1799 dav_error *err;
1801
1802#if DAV_DEBUG
1803 if ((params->walk_type & DAV_WALKTYPE_LOCKNULL) != 0
1804 && params->lockdb == NULL) {
1806 "DESIGN ERROR: walker called to walk locknull "
1807 "resources, but a lockdb was not provided.");
1808 }
1809#endif
1810
1811 fsctx.params = params;
1812 fsctx.wres.walk_ctx = params->walk_ctx;
1813 fsctx.wres.pool = params->pool;
1814
1815 /* ### zero out versioned, working, baselined? */
1816
1817 fsctx.res1 = *params->root;
1818 fsctx.res1.pool = params->pool;
1819
1820 fsctx.res1.info = &fsctx.info1;
1821 fsctx.info1 = *params->root->info;
1822
1823 /* the pathname is stored in the path1 buffer */
1824 dav_buffer_init(params->pool, &fsctx.path1, fsctx.info1.pathname);
1825 fsctx.info1.pathname = fsctx.path1.buf;
1826
1827 if (root_dst != NULL) {
1828 /* internal call from the COPY/MOVE code. set it up. */
1829
1830 fsctx.wres.walk_ctx = &cm_ctx;
1831 cm_ctx.is_move = is_move;
1832 cm_ctx.res_dst = &fsctx.res2;
1833 cm_ctx.root = params->root;
1834 cm_ctx.pool = params->pool;
1835
1836 fsctx.res2 = *root_dst;
1837 fsctx.res2.exists = 0;
1838 fsctx.res2.collection = 0;
1839 fsctx.res2.uri = NULL; /* we don't track this */
1840 fsctx.res2.pool = params->pool;
1841
1842 fsctx.res2.info = &fsctx.info2;
1843 fsctx.info2 = *root_dst->info;
1844
1845 /* res2 does not exist -- clear its finfo structure */
1846 memset(&fsctx.info2.finfo, 0, sizeof(fsctx.info2.finfo));
1847
1848 /* the pathname is stored in the path2 buffer */
1849 dav_buffer_init(params->pool, &fsctx.path2, fsctx.info2.pathname);
1850 fsctx.info2.pathname = fsctx.path2.buf;
1851 }
1852
1853 /* prep the URI buffer */
1854 dav_buffer_init(params->pool, &fsctx.uri_buf, params->root->uri);
1855
1856 /* if we have a directory, then ensure the URI has a trailing "/" */
1857 if (fsctx.res1.collection
1858 && fsctx.uri_buf.buf[fsctx.uri_buf.cur_len - 1] != '/') {
1859
1860 /* this will fall into the pad area */
1861 fsctx.uri_buf.buf[fsctx.uri_buf.cur_len++] = '/';
1862 fsctx.uri_buf.buf[fsctx.uri_buf.cur_len] = '\0';
1863 }
1864
1865 /* the current resource's URI is stored in the uri_buf buffer */
1866 fsctx.res1.uri = fsctx.uri_buf.buf;
1867
1868 /* point the callback's resource at our structure */
1869 fsctx.wres.resource = &fsctx.res1;
1870
1871 /* always return the error, and any/all multistatus responses */
1872 err = dav_fs_walker(&fsctx, depth);
1873 *response = fsctx.wres.response;
1874 return err;
1875}
1876
1877static dav_error * dav_fs_walk(const dav_walk_params *params, int depth,
1878 dav_response **response)
1879{
1880 /* always return the error, and any/all multistatus responses */
1881 return dav_fs_internal_walk(params, depth, 0, NULL, response);
1882}
1883
1884/* dav_fs_etag: Creates an etag for the file path.
1885 */
1886static const char *dav_fs_getetag(const dav_resource *resource)
1887{
1888 etag_rec er;
1889
1891
1892 if (!resource->exists || !ctx->r) {
1893 return "";
1894 }
1895
1896 er.vlist_validator = NULL;
1897 er.request_time = ctx->r->request_time;
1898 er.finfo = &ctx->finfo;
1899 er.pathname = ctx->pathname;
1900 er.fd = NULL;
1901 er.force_weak = 0;
1902
1903 return ap_make_etag_ex(ctx->r, &er);
1904}
1905
1907{
1908 DEBUG_GET_HANDLER, /* normally: special GET handling not required */
1917#if DEBUG_GET_HANDLER
1920#else
1921 NULL,
1922 NULL,
1923#endif
1930 NULL,
1933};
1934
1936 int propid, dav_prop_insert what,
1938{
1939 const char *value;
1940 const char *s;
1941 apr_pool_t *p = resource->info->pool;
1942 const dav_liveprop_spec *info;
1943 long global_ns;
1944
1945 /* an HTTP-date can be 29 chars plus a null term */
1946 /* a 64-bit size can be 20 chars plus a null term */
1947 char buf[DAV_TIMEBUF_SIZE];
1948
1949 /*
1950 ** None of FS provider properties are defined if the resource does not
1951 ** exist. Just bail for this case.
1952 **
1953 ** Even though we state that the FS properties are not defined, the
1954 ** client cannot store dead values -- we deny that thru the is_writable
1955 ** hook function.
1956 */
1957 if (!resource->exists)
1959
1960 switch (propid) {
1962 /*
1963 ** Closest thing to a creation date. since we don't actually
1964 ** perform the operations that would modify ctime (after we
1965 ** create the file), then we should be pretty safe here.
1966 */
1968 resource->info->finfo.ctime,
1969 buf, sizeof(buf));
1970 value = buf;
1971 break;
1972
1974 /* our property, but not defined on collection resources */
1975 if (resource->collection)
1977
1978 apr_snprintf(buf, sizeof(buf), "%" APR_OFF_T_FMT, resource->info->finfo.size);
1979 value = buf;
1980 break;
1981
1982 case DAV_PROPID_getetag:
1984 break;
1985
1988 resource->info->finfo.mtime,
1989 buf, sizeof(buf));
1990 value = buf;
1991 break;
1992
1994 /* our property, but not defined on collection resources */
1995 if (resource->collection)
1997
1998 /* our property, but not defined on this platform */
1999 if (!(resource->info->finfo.valid & APR_FINFO_UPROT))
2001
2002 /* the files are "ours" so we only need to check owner exec privs */
2003 if (resource->info->finfo.protection & APR_UEXECUTE)
2004 value = "T";
2005 else
2006 value = "F";
2007 break;
2008
2009 default:
2010 /* ### what the heck was this property? */
2012 }
2013
2014 /* assert: value != NULL */
2015
2016 /* get the information and global NS index for the property */
2018
2019 /* assert: info != NULL && info->name != NULL */
2020
2021 /* DBG3("FS: inserting lp%d:%s (local %d)", ns, scan->name, scan->ns); */
2022
2023 if (what == DAV_PROP_INSERT_VALUE) {
2024 s = apr_psprintf(p, "<lp%ld:%s>%s</lp%ld:%s>" DEBUG_CR,
2025 global_ns, info->name, value, global_ns, info->name);
2026 }
2027 else if (what == DAV_PROP_INSERT_NAME) {
2028 s = apr_psprintf(p, "<lp%ld:%s/>" DEBUG_CR, global_ns, info->name);
2029 }
2030 else {
2031 /* assert: what == DAV_PROP_INSERT_SUPPORTED */
2032 s = apr_pstrcat(p,
2033 "<D:supported-live-property D:name=\"",
2034 info->name,
2035 "\" D:namespace=\"",
2037 "\"/>" DEBUG_CR, NULL);
2038 }
2040
2041 /* we inserted what was asked for */
2042 return what;
2043}
2044
2045static int dav_fs_is_writable(const dav_resource *resource, int propid)
2046{
2047 const dav_liveprop_spec *info;
2048
2049#ifdef DAV_FS_HAS_EXECUTABLE
2050 /* if we have the executable property, and this isn't a collection,
2051 then the property is writable. */
2052 if (propid == DAV_PROPID_FS_executable && !resource->collection)
2053 return 1;
2054#endif
2055
2057 return info->is_writable;
2058}
2059
2061 const apr_xml_elem *elem,
2062 int operation,
2063 void **context,
2064 int *defer_to_dead)
2065{
2066 const apr_text *cdata;
2067 const apr_text *f_cdata;
2068 char value;
2069 dav_elem_private *priv = elem->priv;
2070
2071 if (priv->propid != DAV_PROPID_FS_executable) {
2072 *defer_to_dead = 1;
2073 return NULL;
2074 }
2075
2076 if (operation == DAV_PROP_OP_DELETE) {
2077 return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
2078 "The 'executable' property cannot be removed.");
2079 }
2080
2081 cdata = elem->first_cdata.first;
2082
2083 /* ### hmm. this isn't actually looking at all the possible text items */
2084 f_cdata = elem->first_child == NULL
2085 ? NULL
2086 : elem->first_child->following_cdata.first;
2087
2088 /* DBG3("name=%s cdata=%s f_cdata=%s",elem->name,cdata ? cdata->text : "[null]",f_cdata ? f_cdata->text : "[null]"); */
2089
2090 if (cdata == NULL) {
2091 if (f_cdata == NULL) {
2092 return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
2093 "The 'executable' property expects a single "
2094 "character, valued 'T' or 'F'. There was no "
2095 "value submitted.");
2096 }
2097 cdata = f_cdata;
2098 }
2099 else if (f_cdata != NULL)
2100 goto too_long;
2101
2102 if (cdata->next != NULL || strlen(cdata->text) != 1)
2103 goto too_long;
2104
2105 value = cdata->text[0];
2106 if (value != 'T' && value != 'F') {
2107 return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
2108 "The 'executable' property expects a single "
2109 "character, valued 'T' or 'F'. The value "
2110 "submitted is invalid.");
2111 }
2112
2113 *context = (void *)((long)(value == 'T'));
2114
2115 return NULL;
2116
2117 too_long:
2118 return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
2119 "The 'executable' property expects a single "
2120 "character, valued 'T' or 'F'. The value submitted "
2121 "has too many characters.");
2122
2123}
2124
2126 const apr_xml_elem *elem,
2127 int operation,
2128 void *context,
2130{
2131 long value = context != NULL;
2132 apr_fileperms_t perms = resource->info->finfo.protection;
2134 long old_value = (perms & APR_UEXECUTE) != 0;
2135
2136 /* assert: prop == executable. operation == SET. */
2137
2138 /* don't do anything if there is no change. no rollback info either. */
2139 /* DBG2("new value=%d (old=%d)", value, old_value); */
2140 if (value == old_value)
2141 return NULL;
2142
2144 if (value)
2146
2147 if ((status = apr_file_perms_set(resource->info->pathname, perms))
2148 != APR_SUCCESS) {
2149 return dav_new_error(resource->info->pool,
2151 "Could not set the executable flag of the "
2152 "target resource.");
2153 }
2154
2155 /* update the resource and set up the rollback context */
2156 resource->info->finfo.protection = perms;
2158
2159 return NULL;
2160}
2161
2163 int operation,
2164 void *context,
2166{
2167 /* nothing to do */
2168}
2169
2171 int operation,
2172 void *context,
2174{
2175 apr_fileperms_t perms = resource->info->finfo.protection & ~APR_UEXECUTE;
2177 int value = rollback_ctx != NULL;
2178
2179 /* assert: prop == executable. operation == SET. */
2180
2181 /* restore the executable bit */
2182 if (value)
2184
2185 if ((status = apr_file_perms_set(resource->info->pathname, perms))
2186 != APR_SUCCESS) {
2187 return dav_new_error(resource->info->pool,
2189 "After a failure occurred, the resource's "
2190 "executable flag could not be restored.");
2191 }
2192
2193 /* restore the resource's state */
2194 resource->info->finfo.protection = perms;
2195
2196 return NULL;
2197}
2198
2199
2201{
2209};
2210
2212{
2216 NULL, /* vsn */
2217 NULL, /* binding */
2218 NULL, /* search */
2219
2220 NULL /* ctx */
2221};
2222
2224{
2225#ifdef DAV_FS_HAS_EXECUTABLE
2226 *(const char **)apr_array_push(uris) =
2227 "<http://apache.org/dav/propset/fs/1>";
2228#endif
2229}
2230
2232 const char *ns_uri, const char *name,
2233 const dav_hooks_liveprop **hooks)
2234{
2235 /* don't try to find any liveprops if this isn't "our" resource */
2236 if (resource->hooks != &dav_hooks_repository_fs)
2237 return 0;
2239}
2240
2243{
2244 /* don't insert any liveprops if this isn't "our" resource */
2245 if (resource->hooks != &dav_hooks_repository_fs)
2246 return;
2247
2248 if (!resource->exists) {
2249 /* a lock-null resource */
2250 /*
2251 ** ### technically, we should insert empty properties. dunno offhand
2252 ** ### what part of the spec said this, but it was essentially thus:
2253 ** ### "the properties should be defined, but may have no value".
2254 */
2255 return;
2256 }
2257
2259 what, phdr);
2261 what, phdr);
2263 what, phdr);
2265 what, phdr);
2266
2267#ifdef DAV_FS_HAS_EXECUTABLE
2268 /* Only insert this property if it is defined for this platform. */
2270 what, phdr);
2271#endif
2272
2273 /* ### we know the others aren't defined as liveprops */
2274}
2275
2277{
2278 /* register the namespace URIs */
2280
2281 /* register the repository provider */
2282 dav_register_provider(p, "filesystem", &dav_fs_provider);
2283}
const char apr_size_t len
Definition ap_regex.h:187
APR-UTIL Buckets/Bucket Brigades.
APR File I/O Handling.
APR Strings library.
#define APLOG_USE_MODULE(foo)
request_rec * r
#define AP_FILTER_ERROR
Definition httpd.h:473
apr_status_t ap_pass_brigade(ap_filter_t *filter, apr_bucket_brigade *bucket)
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_rerror
Definition http_log.h:454
#define APLOG_ERR
Definition http_log.h:67
#define APLOG_MARK
Definition http_log.h:283
const unsigned char * buf
Definition util_md5.h:50
apr_md5_ctx_t * context
Definition util_md5.h:58
void ap_set_etag(request_rec *r)
Definition http_etag.c:367
void ap_set_accept_ranges(request_rec *r)
void ap_set_content_length(request_rec *r, apr_off_t length)
Definition protocol.c:160
void ap_set_last_modified(request_rec *r)
Definition protocol.c:2280
char * ap_make_etag_ex(request_rec *r, etag_rec *er)
Definition http_etag.c:214
void ap_update_mtime(request_rec *r, apr_time_t dependency_mtime)
Definition request.c:2557
#define APR_EOF
Definition apr_errno.h:461
#define APR_INCOMPLETE
Definition apr_errno.h:452
#define APR_ERELATIVE
Definition apr_errno.h:326
#define APR_STATUS_IS_EXDEV(s)
Definition apr_errno.h:1321
#define APR_STATUS_IS_EEXIST(s)
Definition apr_errno.h:1233
#define APR_STATUS_IS_ENOSPC(s)
Definition apr_errno.h:1255
#define APR_STATUS_IS_ENOENT(s)
Definition apr_errno.h:1246
#define APR_BRIGADE_INSERT_TAIL(b, e)
apr_brigade_flush void * ctx
apr_file_t * fd
apr_pool_t apr_dbd_t const char const char * label
Definition apr_dbd.h:397
apr_dbd_transaction_t int mode
Definition apr_dbd.h:261
apr_pool_t const char * params
Definition apr_dbd.h:141
const char const char * pathname
Definition apr_dbm.h:201
const char * src
Definition apr_encode.h:167
const char apr_ssize_t int flags
Definition apr_encode.h:168
void ** resource
const char * uri
Definition apr_uri.h:159
const apr_xml_elem int style
Definition apr_xml.h:287
const apr_xml_elem int apr_array_header_t int const char ** pbuf
Definition apr_xml.h:288
#define HTTP_BAD_REQUEST
Definition httpd.h:508
#define HTTP_MULTI_STATUS
Definition httpd.h:497
#define HTTP_INSUFFICIENT_STORAGE
Definition httpd.h:542
#define HTTP_INTERNAL_SERVER_ERROR
Definition httpd.h:535
#define HTTP_FORBIDDEN
Definition httpd.h:511
#define HTTP_NOT_FOUND
Definition httpd.h:512
#define HTTP_CONFLICT
Definition httpd.h:517
#define ap_is_HTTP_SERVER_ERROR(x)
Definition httpd.h:558
void dav_fs_register(apr_pool_t *p)
Definition repos.c:2276
long dav_get_liveprop_info(int propid, const dav_liveprop_group *group, const dav_liveprop_spec **info)
Definition liveprop.c:111
void dav_buffer_init(apr_pool_t *p, dav_buffer *pbuf, const char *str)
Definition util.c:144
const dav_hooks_db dav_hooks_db_dbm
Definition dbm.c:784
apr_pool_t * dav_fs_pool(const dav_resource *resource)
Definition repos.c:228
void dav_buffer_place_mem(apr_pool_t *p, dav_buffer *pbuf, const void *mem, apr_size_t amt, apr_size_t pad)
Definition util.c:173
const char * dav_fs_pathname(const dav_resource *resource)
Definition repos.c:233
int dav_fs_find_liveprop(const dav_resource *resource, const char *ns_uri, const char *name, const dav_hooks_liveprop **hooks)
Definition repos.c:2231
dav_prop_insert
Definition mod_dav.h:516
void dav_register_liveprop_group(apr_pool_t *p, const dav_liveprop_group *group)
Definition liveprop.c:131
dav_error * dav_fs_dir_file_name(const dav_resource *resource, const char **dirpath_p, const char **fname_p)
Definition repos.c:238
#define DEBUG_CR
Definition mod_dav.h:65
dav_error * dav_lock_query(dav_lockdb *lockdb, const dav_resource *resource, dav_lock **locks)
Definition util_lock.c:369
void dav_dbm_get_statefiles(apr_pool_t *p, const char *fname, const char **state1, const char **state2)
Definition dbm.c:78
#define DAV_TIMEBUF_SIZE
Definition mod_dav.h:538
void dav_check_bufsize(apr_pool_t *p, dav_buffer *pbuf, apr_size_t extra_needed)
Definition util.c:107
#define DAV_INFINITY
Definition mod_dav.h:79
int dav_do_find_liveprop(const char *ns_uri, const char *name, const dav_liveprop_group *group, const dav_hooks_liveprop **hooks)
Definition liveprop.c:83
#define DAV_STYLE_RFC822
Definition mod_dav.h:537
void dav_register_provider(apr_pool_t *p, const char *name, const dav_provider *hooks)
Definition providers.c:24
#define DAV_BUFFER_PAD
Definition mod_dav.h:451
#define DAV_STYLE_ISO8601
Definition mod_dav.h:536
dav_stream_mode
Definition mod_dav.h:1899
dav_error * dav_push_error(apr_pool_t *p, int status, int error_id, const char *desc, dav_error *prev)
Definition util.c:66
dav_error * dav_fs_get_locknull_members(const dav_resource *resource, dav_buffer *pbuf)
Definition lock.c:912
#define DAV_FS_STATE_DIR
Definition repos.h:29
void dav_fs_insert_all_liveprops(request_rec *r, const dav_resource *resource, dav_prop_insert what, apr_text_header *phdr)
Definition repos.c:2241
void dav_set_bufsize(apr_pool_t *p, dav_buffer *pbuf, apr_size_t size)
Definition util.c:122
dav_error * dav_new_error(apr_pool_t *p, int status, int error_id, apr_status_t aprerr, const char *desc)
Definition util.c:36
void dav_add_response(dav_walk_resource *wres, int status, dav_get_props_result *propstats)
Definition mod_dav.c:1245
void dav_fs_gather_propsets(apr_array_header_t *uris)
Definition repos.c:2223
struct dav_liveprop_rollback dav_liveprop_rollback
Definition mod_dav.h:887
@ DAV_PROPID_getcontentlength
Definition mod_dav.h:1120
@ DAV_PROPID_getetag
Definition mod_dav.h:1122
@ DAV_PROPID_creationdate
Definition mod_dav.h:1117
@ DAV_PROPID_getlastmodified
Definition mod_dav.h:1123
@ DAV_PROP_INSERT_NAME
Definition mod_dav.h:525
@ DAV_PROP_INSERT_VALUE
Definition mod_dav.h:527
@ DAV_PROP_INSERT_NOTDEF
Definition mod_dav.h:517
@ DAV_MODE_WRITE_SEEKABLE
Definition mod_dav.h:1901
@ DAV_MODE_WRITE_TRUNC
Definition mod_dav.h:1900
@ DAV_CALLTYPE_LOCKNULL
Definition mod_dav.h:1797
@ DAV_CALLTYPE_COLLECTION
Definition mod_dav.h:1796
@ DAV_CALLTYPE_MEMBER
Definition mod_dav.h:1795
@ DAV_RESOURCE_TYPE_VERSION
Definition mod_dav.h:303
@ DAV_RESOURCE_TYPE_REGULAR
Definition mod_dav.h:299
@ DAV_RESOURCE_TYPE_WORKING
Definition mod_dav.h:307
char * ap_make_dirstr_parent(apr_pool_t *p, const char *s)
Definition util.c:692
#define ap_assert(exp)
Definition httpd.h:2271
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
char apr_size_t bufsize
Definition apr_errno.h:53
int apr_status_t
Definition apr_errno.h:44
apr_int32_t apr_fileperms_t
@ APR_REG
@ APR_DIR
@ APR_NOFILE
const char apr_fileperms_t perms
char * templ
apr_seek_where_t apr_off_t * offset
void * data
#define APR_READ
Definition apr_file_io.h:93
#define APR_BINARY
Definition apr_file_io.h:98
#define APR_EXCL
Definition apr_file_io.h:99
#define APR_WRITE
Definition apr_file_io.h:94
#define APR_TRUNCATE
Definition apr_file_io.h:97
#define APR_FOPEN_EXCL
Definition apr_file_io.h:63
#define APR_CREATE
Definition apr_file_io.h:95
#define APR_UEXECUTE
#define APR_OS_DEFAULT
#define APR_SET
#define APR_FINFO_INODE
const char * fname
#define APR_FINFO_DIRENT
#define APR_FINFO_UPROT
#define APR_FINFO_NORM
#define APR_FINFO_PROT
const char * rootpath
apr_array_header_t ** result
apr_size_t buflen
apr_interval_time_t apr_int32_t * num
Definition apr_poll.h:273
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
apr_size_t const char * filename
Definition apr_shm.h:72
const char * s
Definition apr_strings.h:95
apr_int32_t apr_int32_t apr_int32_t err
int int status
APR_DECLARE_DATA const char apr_month_snames[12][4]
Definition timestr.c:33
APR_DECLARE_DATA const char apr_day_snames[7][4]
Definition timestr.c:37
apr_int64_t apr_time_t
Definition apr_time.h:45
Apache Logging library.
HTTP protocol handling.
Apache Request library.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
DAV extension module for Apache 2.0.*.
#define DAV_WALKTYPE_AUTH
Definition mod_dav.h:1819
#define DAV_WALKTYPE_TOLERANT
Definition mod_dav.h:1822
#define DAV_PROP_OP_DELETE
Definition mod_dav.h:1766
#define DAV_WALKTYPE_LOCKNULL
Definition mod_dav.h:1821
#define DAV_WALKTYPE_NORMAL
Definition mod_dav.h:1820
static const char *const hooks[]
return NULL
Definition mod_so.c:359
static const dav_liveprop_spec dav_fs_props[]
Definition repos.c:149
static apr_status_t dav_fs_mktemp(apr_file_t **fp, char *templ, apr_pool_t *p)
Definition repos.c:888
static dav_error * dav_fs_patch_rollback(const dav_resource *resource, int operation, void *context, dav_liveprop_rollback *rollback_ctx)
Definition repos.c:2170
static dav_error * dav_fs_seek_stream(dav_stream *stream, apr_off_t abs_pos)
Definition repos.c:1038
#define DAV_FS_TMP_PREFIX
Definition repos.c:147
static dav_error * dav_fs_walk(const dav_walk_params *params, int depth, dav_response **response)
Definition repos.c:1877
static dav_error * dav_fs_close_stream(dav_stream *stream, int commit)
Definition repos.c:983
static dav_prop_insert dav_fs_insert_prop(const dav_resource *resource, int propid, dav_prop_insert what, apr_text_header *phdr)
Definition repos.c:1935
static const char *const dav_fs_namespace_uris[]
Definition repos.c:108
#define DAV_WALKTYPE_HIDDEN
Definition repos.c:89
static dav_error * dav_fs_patch_exec(const dav_resource *resource, const apr_xml_elem *elem, int operation, void *context, dav_liveprop_rollback **rollback_ctx)
Definition repos.c:2125
static dav_error * dav_fs_copymove_walker(dav_walk_resource *wres, int calltype)
Definition repos.c:1162
static const dav_liveprop_group dav_fs_liveprop_group
Definition repos.c:188
#define DAV_WALKTYPE_POSTFIX
Definition repos.c:92
static const dav_provider dav_fs_provider
Definition repos.c:2211
@ DAV_FS_URI_DAV
Definition repos.c:116
@ DAV_FS_URI_MYPROPS
Definition repos.c:117
static dav_error * dav_fs_internal_walk(const dav_walk_params *params, int depth, int is_move, const dav_resource *root_dst, dav_response **response)
Definition repos.c:1793
static dav_error * dav_fs_get_parent_resource(const dav_resource *resource, dav_resource **result_parent)
Definition repos.c:773
static dav_error * dav_fs_deleteset(apr_pool_t *p, const dav_resource *resource)
Definition repos.c:613
static int dav_fs_is_writable(const dav_resource *resource, int propid)
Definition repos.c:2045
static dav_error * dav_fs_write_stream(dav_stream *stream, const void *buf, apr_size_t bufsize)
Definition repos.c:1018
#define DAV_FINFO_MASK
Definition repos.c:130
static const char * dav_fs_getetag(const dav_resource *resource)
Definition repos.c:1886
static dav_error * dav_fs_delete_walker(dav_walk_resource *wres, int calltype)
Definition repos.c:1410
static int dav_fs_is_same_resource(const dav_resource *res1, const dav_resource *res2)
Definition repos.c:839
const dav_hooks_locks dav_hooks_locks_fs
Definition lock.c:1426
static void dav_format_time(int style, apr_time_t sec, char *buf, apr_size_t buflen)
Definition repos.c:297
static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth)
Definition repos.c:1504
static int dav_fs_is_parent_resource(const dav_resource *res1, const dav_resource *res2)
Definition repos.c:858
static const dav_hooks_repository dav_hooks_repository_fs
Definition repos.c:101
static dav_error * dav_fs_copy_resource(const dav_resource *src, dav_resource *dst, int depth, dav_response **response)
Definition repos.c:1286
static request_rec * dav_fs_get_request_rec(const dav_resource *resource)
Definition repos.c:223
static dav_error * dav_fs_move_resource(dav_resource *src, dav_resource *dst, dav_response **response)
Definition repos.c:1317
static dav_error * dav_fs_copymove_resource(int is_move, const dav_resource *src, const dav_resource *dst, int depth, dav_response **response)
Definition repos.c:1224
#define DAV_CALLTYPE_POSTFIX
Definition repos.c:94
static dav_error * dav_fs_patch_validate(const dav_resource *resource, const apr_xml_elem *elem, int operation, void **context, int *defer_to_dead)
Definition repos.c:2060
#define DAV_PROPID_FS_executable
Definition repos.c:142
static dav_error * dav_fs_get_resource(request_rec *r, const char *root_dir, const char *label, int use_checked_in, dav_resource **result_resource)
Definition repos.c:667
#define DEBUG_GET_HANDLER
Definition repos.c:41
static dav_error * dav_fs_copymoveset(int is_move, apr_pool_t *p, const dav_resource *src, const dav_resource *dst, dav_buffer *pbuf)
Definition repos.c:554
static dav_error * dav_fs_copymove_state(int is_move, apr_pool_t *p, const char *src_dir, const char *src_file, const char *dst_dir, const char *dst_file, dav_buffer *pbuf)
Definition repos.c:475
static const dav_hooks_liveprop dav_hooks_liveprop_fs
Definition repos.c:102
static dav_error * dav_fs_open_stream(const dav_resource *resource, dav_stream_mode mode, dav_stream **stream)
Definition repos.c:908
static apr_status_t tmpfile_cleanup(void *data)
Definition repos.c:878
static dav_error * dav_fs_copymove_file(int is_move, apr_pool_t *p, const char *src, const char *dst, const apr_finfo_t *src_finfo, const apr_finfo_t *dst_finfo, dav_buffer *pbuf)
Definition repos.c:327
static dav_error * dav_fs_create_collection(dav_resource *resource)
Definition repos.c:1133
static dav_error * dav_fs_remove_resource(dav_resource *resource, dav_response **response)
Definition repos.c:1444
static void dav_fs_patch_commit(const dav_resource *resource, int operation, void *context, dav_liveprop_rollback *rollback_ctx)
Definition repos.c:2162
#define DAV_FS_COPY_BLOCKSIZE
Definition repos.c:43
#define MAP_IO2HTTP(e)
Definition repos.c:207
Declarations for the filesystem repository implementation.
char * name
The representation of a filter chain.
conn_rec * c
apr_finfo_t * finfo
apr_filetype_e filetype
apr_off_t size
apr_ino_t inode
apr_time_t mtime
struct apr_bucket_alloc_t * bucket_alloc
Definition httpd.h:1201
const dav_resource * root
Definition repos.c:83
dav_buffer work_buf
Definition repos.c:77
apr_pool_t * pool
Definition repos.c:84
const dav_resource * res_dst
Definition repos.c:80
dav_resource res1
Definition repos.c:61
dav_resource_private info2
Definition repos.c:68
const dav_walk_params * params
Definition repos.c:56
dav_walk_resource wres
Definition repos.c:59
dav_buffer uri_buf
Definition repos.c:64
dav_buffer path1
Definition repos.c:63
dav_buffer path2
Definition repos.c:69
dav_resource_private info1
Definition repos.c:62
dav_buffer locknull_buf
Definition repos.c:71
dav_resource res2
Definition repos.c:67
apr_finfo_t finfo
Definition repos.c:49
const char * pathname
Definition repos.c:48
request_rec * r
Definition repos.c:50
apr_pool_t * pool
Definition repos.c:47
dav_resource_private * info
Definition mod_dav.h:412
const char * uri
Definition mod_dav.h:408
const dav_hooks_repository * hooks
Definition mod_dav.h:414
apr_pool_t * pool
Definition mod_dav.h:419
int collection
Definition mod_dav.h:392
char * temppath
Definition repos.c:201
const char * pathname
Definition repos.c:200
apr_pool_t * p
Definition repos.c:198
apr_file_t * f
Definition repos.c:199
int unlink_on_error
Definition repos.c:202
const dav_resource * resource
Definition mod_dav.h:1809
apr_pool_t * pool
Definition mod_dav.h:1806
A structure with the ingredients for a file based etag.
A structure that represents the current request.
Definition httpd.h:845
char * uri
Definition httpd.h:1016
apr_pool_t * pool
Definition httpd.h:847
char * filename
Definition httpd.h:1018
apr_time_t request_time
Definition httpd.h:886
apr_finfo_t finfo
Definition httpd.h:1094
char * path_info
Definition httpd.h:1024
abts_suite * testpath(abts_suite *suite)
Definition testpath.c:127
apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, apr_dir_t *thedir)
Definition dir.c:142
apr_status_t apr_dir_make(const char *path, apr_fileperms_t perm, apr_pool_t *pool)
Definition dir.c:297
apr_status_t apr_dir_remove(const char *path, apr_pool_t *pool)
Definition dir.c:343
apr_status_t apr_dir_close(apr_dir_t *thedir)
Definition dir.c:109
apr_status_t apr_dir_open(apr_dir_t **new, const char *dirname, apr_pool_t *pool)
Definition dir.c:75
INT info