842ae4bd224140319ae7feec1872b93dfd491143fielding/* Licensed to the Apache Software Foundation (ASF) under one or more
842ae4bd224140319ae7feec1872b93dfd491143fielding * contributor license agreements. See the NOTICE file distributed with
842ae4bd224140319ae7feec1872b93dfd491143fielding * this work for additional information regarding copyright ownership.
842ae4bd224140319ae7feec1872b93dfd491143fielding * The ASF licenses this file to You under the Apache License, Version 2.0
842ae4bd224140319ae7feec1872b93dfd491143fielding * (the "License"); you may not use this file except in compliance with
842ae4bd224140319ae7feec1872b93dfd491143fielding * the License. You may obtain a copy of the License at
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Unless required by applicable law or agreed to in writing, software
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * distributed under the License is distributed on an "AS IS" BASIS,
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * See the License for the specific language governing permissions and
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * limitations under the License.
f4c310fd2555c6faca1f980f00b161eadb089023gstein** DAV filesystem-based repository provider
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#include "http_protocol.h" /* for ap_set_* (in dav_fs_set_headers) */
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* to assist in debugging mod_dav's GET handling */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe#define DAV_FS_COPY_BLOCKSIZE 16384 /* copy 16k at a time */
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* context needed to identify a resource */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm apr_pool_t *pool; /* memory storage pool associated with request */
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *pathname; /* full pathname to resource */
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* private context for doing a filesystem walk */
f4c310fd2555c6faca1f980f00b161eadb089023gsteintypedef struct {
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein /* the input walk parameters */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein /* reused as we walk */
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* MOVE/COPY need a secondary path */
707ecf9559338ec06b24334bc9abcca670325cc4gsteintypedef struct {
707ecf9559338ec06b24334bc9abcca670325cc4gstein dav_buffer work_buf; /* handy buffer for copymove_file() */
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* CALLBACK: this is a secondary resource managed specially for us */
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* copied from dav_walk_params (they are invariant across the walk) */
707ecf9559338ec06b24334bc9abcca670325cc4gstein/* an internal WALKTYPE to walk hidden files (the .DAV directory) */
707ecf9559338ec06b24334bc9abcca670325cc4gstein/* an internal WALKTYPE to call collections (again) after their contents */
707ecf9559338ec06b24334bc9abcca670325cc4gstein#define DAV_CALLTYPE_POSTFIX 1000 /* a private call type */
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* pull this in from the other source file */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein/* forward-declare the hook structures */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const dav_hooks_repository dav_hooks_repository_fs;
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic const dav_hooks_liveprop dav_hooks_liveprop_fs;
f4c310fd2555c6faca1f980f00b161eadb089023gstein** The namespace URIs that we use. This list and the enumeration must
f4c310fd2555c6faca1f980f00b161eadb089023gstein** stay in sync.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe DAV_FS_URI_MYPROPS /* the namespace URI for our custom props */
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein** Does this platform support an executable flag?
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein** ### need a way to portably abstract this query
c70afa1853413eb72c4909354c2814d89e9b99f7jorton** DAV_FINFO_MASK gives the appropriate mask to use for the stat call
c70afa1853413eb72c4909354c2814d89e9b99f7jorton** used to get file attributes.
c70afa1853413eb72c4909354c2814d89e9b99f7jorton#define DAV_FINFO_MASK (APR_FINFO_LINK | APR_FINFO_TYPE | APR_FINFO_INODE | \
c70afa1853413eb72c4909354c2814d89e9b99f7jorton APR_FINFO_SIZE | APR_FINFO_CTIME | APR_FINFO_MTIME | \
c70afa1853413eb72c4909354c2814d89e9b99f7jorton/* as above, but without APR_FINFO_PROT */
c70afa1853413eb72c4909354c2814d89e9b99f7jorton#define DAV_FINFO_MASK (APR_FINFO_LINK | APR_FINFO_TYPE | APR_FINFO_INODE | \
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein** The single property that we define (in the DAV_FS_URI_MYPROPS namespace)
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf * prefix for temporary files
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein /* standard DAV properties */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein "creationdate",
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein "getcontentlength",
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein "getlastmodified",
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein /* our custom properties */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein "executable",
956f4b1551215610a57f3b52822dbac6f41a8aa9gstein 0 /* handled special in dav_fs_is_writable */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe { 0 } /* sentinel */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gsteinstatic const dav_liveprop_group dav_fs_liveprop_group =
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* define the dav_stream structure for our use */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe const char *pathname; /* we may need to remove it at close time */
e8f95a682820a599fe41b22977010636be5c2717jim/* returns an appropriate HTTP status code given an APR status code for a
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton * failed I/O operation. ### use something besides 500? */
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton#define MAP_IO2HTTP(e) (APR_STATUS_IS_ENOSPC(e) ? HTTP_INSUFFICIENT_STORAGE : \
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* forward declaration for internal treewalkers */
f94aab38f6ee899f463f0118ea395291f7c5b4cegsteinstatic dav_error * dav_fs_walk(const dav_walk_params *params, int depth,
707ecf9559338ec06b24334bc9abcca670325cc4gsteinstatic dav_error * dav_fs_internal_walk(const dav_walk_params *params,
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* --------------------------------------------------------------------
f4c310fd2555c6faca1f980f00b161eadb089023gstein** PRIVATE REPOSITORY FUNCTIONS
a0c5ae524801374f36b3769d33d32ea1cca5ade3fuankgstatic request_rec *dav_fs_get_request_rec(const dav_resource *resource)
f4c310fd2555c6faca1f980f00b161eadb089023gsteinconst char *dav_fs_pathname(const dav_resource *resource)
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char **dirpath_p,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char **fname_p)
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *dirpath = ap_make_dirstr_parent(ctx->pool, ctx->pathname);
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe rv = apr_filepath_root(&rootpath, &testpath, 0, ctx->pool);
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe /* remove trailing slash from dirpath, unless it's a root path
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe /* ###: Looks like a response could be appropriate
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe * APR_SUCCESS here tells us the dir is a root
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe * APR_ERELATIVE told us we had no root (ok)
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe * APR_EINCOMPLETE an incomplete testpath told us
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe * there was no -file- name here!
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe * APR_EBADPATH or other errors tell us this file
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe * path is undecipherable
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(ctx->pool, HTTP_INTERNAL_SERVER_ERROR, 0, rv,
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein "An incomplete/bad path was found in "
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein "dav_fs_dir_file_name.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Note: picked up from ap_gm_timestr_822() */
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* NOTE: buf must be at least DAV_TIMEBUF_SIZE chars in size */
dc52cac281d8b311dc47d115ed979f923b667679rjungstatic void dav_format_time(int style, apr_time_t sec, char *buf, apr_size_t buflen)
f71d4ec448449837beefe21cf7c9f8d9b6bd4654gstein /* ### what to do if fails? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### should we use "-00:00" instead of "Z" ?? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* 20 chars plus null term */
dc52cac281d8b311dc47d115ed979f923b667679rjung apr_snprintf(buf, buflen, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2dZ",
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* RFC 822 date format; as strftime '%a, %d %b %Y %T GMT' */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* 29 chars plus null term */
dc52cac281d8b311dc47d115ed979f923b667679rjung apr_snprintf(buf, buflen, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT",
7f69a90d847f08a86f9909c2c5129408697a9600jorton/* Copy or move src to dst; src_finfo is used to propagate permissions
7f69a90d847f08a86f9909c2c5129408697a9600jorton * bits across if non-NULL; dst_finfo must be non-NULL iff dst already
7f69a90d847f08a86f9909c2c5129408697a9600jorton * exists. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *src,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *dst,
7f69a90d847f08a86f9909c2c5129408697a9600jorton /* Determine permissions to use for destination */
7f69a90d847f08a86f9909c2c5129408697a9600jorton /* chmod it if it already exist */
99d46a23c6eac800f327b29f8009f7d7da986230trawick if ((status = apr_file_perms_set(dst, perms)) != APR_SUCCESS) {
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, status,
7f69a90d847f08a86f9909c2c5129408697a9600jorton "Could not set permissions on destination");
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim if ((status = apr_file_open(&inf, src, APR_READ | APR_BINARY,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### use something besides 500? */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, status,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not open file for reading");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ### do we need to deal with the umask? */
e8f95a682820a599fe41b22977010636be5c2717jim status = apr_file_open(&outf, dst, APR_WRITE | APR_CREATE | APR_TRUNCATE
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, MAP_IO2HTTP(status), 0, status,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not open file for writing");
f4c310fd2555c6faca1f980f00b161eadb089023gstein while (1) {
99d46a23c6eac800f327b29f8009f7d7da986230trawick if ((lcl_status = apr_file_remove(dst, p)) != APR_SUCCESS) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### ACK! Inconsistent state... */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### use something besides 500? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not delete output after read "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "failure. Server is now in an "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "inconsistent state.");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### use something besides 500? */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, status,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not read input file");
7ac747af0cf476c2276aaf9999425e1b52bf5f64jorton /* write any bytes that were read */
9ec6440fdeb81f04905959293b381ebbfa3114c2jorton status = apr_file_write_full(outf, pbuf->buf, len, NULL);
99d46a23c6eac800f327b29f8009f7d7da986230trawick if ((lcl_status = apr_file_remove(dst, p)) != APR_SUCCESS) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### ACK! Inconsistent state... */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### use something besides 500? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not delete output after write "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "failure. Server is now in an "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "inconsistent state.");
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, MAP_IO2HTTP(status), 0, status,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not write output file");
4dcb341a20cfcfdfa7dbe1faad88ce8de6a413f0sf if (is_move && (status = apr_file_remove(src, p)) != APR_SUCCESS) {
4dcb341a20cfcfdfa7dbe1faad88ce8de6a413f0sf * Something is wrong here but the result is what we wanted.
4dcb341a20cfcfdfa7dbe1faad88ce8de6a413f0sf * We definitely should not remove the destination file.
99d46a23c6eac800f327b29f8009f7d7da986230trawick err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, status,
4dcb341a20cfcfdfa7dbe1faad88ce8de6a413f0sf "file %s after move to %s. The "
4dcb341a20cfcfdfa7dbe1faad88ce8de6a413f0sf "server may be in an "
99d46a23c6eac800f327b29f8009f7d7da986230trawick else if ((lcl_status = apr_file_remove(dst, p)) != APR_SUCCESS) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### ACK. this creates an inconsistency. do more!? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### use something besides 500? */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, lcl_status,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not remove source or destination "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "file. Server is now in an inconsistent "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### use something besides 500? */
99d46a23c6eac800f327b29f8009f7d7da986230trawick err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, status,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not remove source file after move. "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Destination was removed to ensure consistency.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* copy/move a file from within a state dir to another state dir */
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* ### need more buffers to replace the pool argument */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_finfo_t dst_state_finfo; /* finfo for STATE directory */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* build the propset pathname for the source file */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm src = apr_pstrcat(p, src_dir, "/" DAV_FS_STATE_DIR "/", src_file, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* the source file doesn't exist */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* build the pathname for the destination state dir */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm dst = apr_pstrcat(p, dst_dir, "/" DAV_FS_STATE_DIR, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ### do we need to deal with the umask? */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ensure that it exists */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### use something besides 500? */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, rv,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not create internal state directory");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* get info about the state directory */
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe rv = apr_stat(&dst_state_finfo, dst, APR_FINFO_NORM, p);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* Ack! Where'd it go? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### use something besides 500? */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, rv,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "State directory disappeared");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* The mkdir() may have failed because a *file* exists there already */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### try to recover by deleting this file? (and mkdir again) */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### use something besides 500? */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "State directory is actually a file");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* append the target file to the state directory pathname */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* copy/move the file now */
490062b5568680531b35102c60228d1802fcdb23sf /* try simple rename first */
490062b5568680531b35102c60228d1802fcdb23sf return dav_fs_copymove_file(is_move, p, src, dst, NULL, NULL, pbuf);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### use something besides 500? */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, rv,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not move state file.");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* gotta copy (and delete) */
7f69a90d847f08a86f9909c2c5129408697a9600jorton return dav_fs_copymove_file(is_move, p, src, dst, NULL, NULL, pbuf);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic dav_error *dav_fs_copymoveset(int is_move, apr_pool_t *p,
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Get directory and filename for resources */
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein /* ### should test these result values... */
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein (void) dav_fs_dir_file_name(src, &src_dir, &src_file);
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein (void) dav_fs_dir_file_name(dst, &dst_dir, &dst_file);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Get the corresponding state files for each resource */
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_dbm_get_statefiles(p, src_file, &src_state1, &src_state2);
f4c310fd2555c6faca1f980f00b161eadb089023gstein dav_dbm_get_statefiles(p, dst_file, &dst_state1, &dst_state2);
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "DESIGN ERROR: dav_dbm_get_statefiles() "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "returned inconsistent results.");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### CRAP. inconsistency. */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### should perform some cleanup at the target if we still
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### have the original files */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* Change the error to reflect the bad server state. */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not fully copy/move the properties. "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The server is now in an inconsistent state.";
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic dav_error *dav_fs_deleteset(apr_pool_t *p, const dav_resource *resource)
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Get directory, filename, and state-file names for the resource */
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein /* ### should test this result value... */
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein (void) dav_fs_dir_file_name(resource, &dirpath, &fname);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* build the propset pathname for the file */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* note: we may get ENOENT if the state dir is not present */
da9adab0554faf94f8cc2705c2363aceacf75c46gstein if ((status = apr_file_remove(pathname, p)) != APR_SUCCESS
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, status,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not remove properties.");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* build the propset pathname for the file */
da9adab0554faf94f8cc2705c2363aceacf75c46gstein if ((status = apr_file_remove(pathname, p)) != APR_SUCCESS
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### CRAP. only removed half. */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0, status,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not fully remove properties. "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The server is now in an inconsistent "
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* --------------------------------------------------------------------
f4c310fd2555c6faca1f980f00b161eadb089023gstein** REPOSITORY HOOK FUNCTIONS
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *root_dir,
f39230a531b23d94f86a087963299bbe2e431a4agstein const char *label,
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ### optimize this into a single allocation! */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Create private resource context descriptor */
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein /* ### this should go away */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Preserve case on OSes which fold canonical filenames */
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein /* ### not available in Apache 2.0 yet */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** If there is anything in the path_info, then this indicates that the
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** entire path was not used to specify the file/dir. We want to append
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** it onto the filename so that we get a "valid" pathname for null
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** resources.
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm s = apr_pstrcat(r->pool, filename, r->path_info, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* make sure the pathname does not have a trailing "/" */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Create resource descriptor */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* make sure the URI does not have a trailing "/" */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* unused info in the URL will indicate a null resource */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* only a trailing "/" is allowed */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if (*r->path_info != '/' || r->path_info[1] != '\0') {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** This URL/filename represents a locknull resource or
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** possibly a destination of a MOVE/COPY
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** The base of the path refers to a file -- nothing should
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** be in path_info. The resource is simply an error: it
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** can't be a null or a locknull resource.
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, 0,
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein "The URL contains extraneous path "
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein "components. The resource could not "
866b521be8a30b2798ad3c3b73de5e965edd7c2fgstein "be identified.");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* retain proper integrity across the structures */
866b521be8a30b2798ad3c3b73de5e965edd7c2fgsteinstatic dav_error * dav_fs_get_parent_resource(const dav_resource *resource,
cc8241a7ee9815575a267e13eff62b6fddf1fe58gstein /* If we're at the root of the URL space, then there is no parent. */
8fbfbe227895f4752c9bfd99b89f303f508610f4wrowe /* If given resource is root, then there is no parent.
8fbfbe227895f4752c9bfd99b89f303f508610f4wrowe * Unless we can retrieve the filepath root, this is
8fbfbe227895f4752c9bfd99b89f303f508610f4wrowe * intendend to fail. If we split the root and
8fbfbe227895f4752c9bfd99b89f303f508610f4wrowe * no path info remains, then we also fail.
e2c92fb4350c626885aff64d3f92690a1892ca50wrowe rv = apr_filepath_root(&testroot, &testpath, 0, ctx->pool);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ### optimize this into a single allocation! */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Create private resource context descriptor */
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm parent_ctx = apr_pcalloc(ctx->pool, sizeof(*parent_ctx));
ba2ad3b1bb4a729278ad8e8846d34ddd27b6551cgstein /* ### this should go away */
f4c310fd2555c6faca1f980f00b161eadb089023gstein dirpath = ap_make_dirstr_parent(ctx->pool, ctx->pathname);
e8f95a682820a599fe41b22977010636be5c2717jim if (strlen(dirpath) > 1 && dirpath[strlen(dirpath) - 1] == '/')
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm parent_resource = apr_pcalloc(ctx->pool, sizeof(*parent_resource));
f4c310fd2555c6faca1f980f00b161eadb089023gstein char *uri = ap_make_dirstr_parent(ctx->pool, resource->uri);
2d4ea77e21ef7f3707d2c27f6117cc0a36e99b83trawick if ((ctx1->finfo.filetype != APR_NOFILE) && (ctx2->finfo.filetype != APR_NOFILE)
2f40d5ac42ba2e7a8043eca56b5f5d8dce101f94wrowe && (ctx1->finfo.valid & ctx2->finfo.valid & APR_FINFO_INODE)) {
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* it is safe to use ctx2 now */
9e7795ba458e905b76861ed4ee13fa11bacd4d2dsf/* custom mktemp that creates the file with APR_OS_DEFAULT permissions */
9e7795ba458e905b76861ed4ee13fa11bacd4d2dsfstatic apr_status_t dav_fs_mktemp(apr_file_t **fp, char *templ, apr_pool_t *p)
a9cb1e4a5aa12b156a3645d5be1dc2095759aa88rpluem int num = ((getpid() << 7) + (apr_uintptr_t)templ % (1 << 16) ) %
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic dav_error * dav_fs_open_stream(const dav_resource *resource,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe flags = APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_BINARY;
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf ds->temppath = apr_pstrcat(p, ap_make_dirstr_parent(p, ds->pathname),
17d64c884a44f5ca72f6901afd3e50991bfc1c63sf rv = apr_file_open(&ds->f, ds->pathname, flags | APR_FOPEN_EXCL,
17d64c884a44f5ca72f6901afd3e50991bfc1c63sf /* we have created a new file */
17d64c884a44f5ca72f6901afd3e50991bfc1c63sf rv = apr_file_open(&ds->f, ds->pathname, flags, APR_OS_DEFAULT,
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf rv = apr_file_open(&ds->f, ds->pathname, flags, APR_OS_DEFAULT, ds->p);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "An error occurred while opening a resource.");
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein /* (APR registers cleanups for the fd with the pool) */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic dav_error * dav_fs_close_stream(dav_stream *stream, int commit)
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf apr_pool_cleanup_run(stream->p, stream, tmpfile_cleanup);
99d46a23c6eac800f327b29f8009f7d7da986230trawick if ((rv = apr_file_remove(stream->pathname, stream->p))
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf /* ### use a better description? */
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0,
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf "There was a problem removing (rolling "
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf "back) the resource "
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf "when it was being closed.");
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf rv = apr_file_rename(stream->temppath, stream->pathname, stream->p);
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, rv,
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf "There was a problem writing the file "
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf "atomically after writes.");
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf apr_pool_cleanup_kill(stream->p, stream, tmpfile_cleanup);
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic dav_error * dav_fs_write_stream(dav_stream *stream,
066877f1a045103acfdd376d48cdd473c33f409bdougm status = apr_file_write_full(stream->f, buf, bufsize, NULL);
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(stream->p, HTTP_INSUFFICIENT_STORAGE, 0, status,
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein "There is not enough storage to write to "
1f6e6566a4ce31a0b95d5400c36d0aaff7a6e94agstein "this resource.");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### use something besides 500? */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, status,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "An error occurred while writing to a "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "resource.");
1ccd992d37d62c8cb2056126f2234f64ec189bfddougmstatic dav_error * dav_fs_seek_stream(dav_stream *stream, apr_off_t abs_pos)
99d46a23c6eac800f327b29f8009f7d7da986230trawick if ((status = apr_file_seek(stream->f, APR_SET, &abs_pos))
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### should check whether apr_file_seek set abs_pos was set to the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * correct position? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### use something besides 500? */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(stream->p, HTTP_INTERNAL_SERVER_ERROR, 0, status,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not seek to specified position in the "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "resource.");
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein/* only define set_headers() and deliver() for debug purposes */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ### this function isn't really used since we have a get_pathname */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* make sure the proper mtime is in the request record */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ### note that these use r->filename rather than <resource> */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* we accept byte-ranges */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* set up the Content-Length header */
f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbdagstein ap_set_content_length(r, resource->info->finfo.size);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ### how to set the content type? */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ### until this is resolved, the Content-Type header is busted */
b6c56e35c5ebdbe1da09806714fb579f3b8c648egsteinstatic dav_error * dav_fs_deliver(const dav_resource *resource,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein /* Check resource type */
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein "Cannot GET this type of resource.");
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein "There is no default response to GET for a "
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein "collection.");
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein if ((status = apr_file_open(&fd, resource->info->pathname,
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(pool, HTTP_FORBIDDEN, 0, status,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein "File permissions deny server access.");
2fc50921b88defeb7127985dfe4b4130175e069ejwoolley bb = apr_brigade_create(pool, output->c->bucket_alloc);
0c9166d0186cf0e1ad397025f730ae6967f44ce6jorton apr_brigade_insert_file(bb, fd, 0, resource->info->finfo.size, pool);
2fc50921b88defeb7127985dfe4b4130175e069ejwoolley bkt = apr_bucket_eos_create(output->c->bucket_alloc);
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein if ((status = ap_pass_brigade(output, bb)) != APR_SUCCESS) {
1715880355ef7f574cae2e8f973411b51acededeylavic return dav_new_error(pool, AP_FILTER_ERROR, 0, status,
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein "Could not write contents to filter.");
b6c56e35c5ebdbe1da09806714fb579f3b8c648egstein#endif /* DEBUG_GET_HANDLER */
33397e35239f202a595837571561468f02b2e806gsteinstatic dav_error * dav_fs_create_collection(dav_resource *resource)
066877f1a045103acfdd376d48cdd473c33f409bdougm status = apr_dir_make(ctx->pathname, APR_OS_DEFAULT, ctx->pool);
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(ctx->pool, HTTP_INSUFFICIENT_STORAGE, 0, status,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "There is not enough storage to create "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "this collection.");
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(ctx->pool, HTTP_CONFLICT, 0, status,
51a61c00a9edcd1d249b9d912681c0c10b8be409jorton "Cannot create collection; intermediate "
51a61c00a9edcd1d249b9d912681c0c10b8be409jorton "collection does not exist.");
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### refine this error message? */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(ctx->pool, HTTP_FORBIDDEN, 0, status,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Unable to create collection.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* update resource state to show it exists as a collection */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gsteinstatic dav_error * dav_fs_copymove_walker(dav_walk_resource *wres,
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein dav_resource_private *srcinfo = wres->resource->info;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* Postfix call for MOVE. delete the source dir.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe * Note: when copying, we do not enable the postfix-traversal.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### we are ignoring any error here; what should we do? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* copy/move of a collection. Create the new, target collection */
99d46a23c6eac800f327b29f8009f7d7da986230trawick if ((status = apr_dir_make(dstinfo->pathname, APR_OS_DEFAULT,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### assume it was a permissions problem */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### need a description here */
99d46a23c6eac800f327b29f8009f7d7da986230trawick err = dav_new_error(ctx->pool, HTTP_FORBIDDEN, 0, status, NULL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### push a higher-level description? */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** If we have a "not so bad" error, then it might need to go into a
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** multistatus response.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** For a MOVE, it will always go into the multistatus. It could be
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** that everything has been moved *except* for the root. Using a
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** multistatus (with no errors for the other resources) will signify
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** this condition.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** For a COPY, we are traversing in a prefix fashion. If the root fails,
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** then we can just bail out now.
707ecf9559338ec06b24334bc9abcca670325cc4gstein || !dav_fs_is_same_resource(wres->resource, ctx->root))) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### use errno to generate DAV:responsedescription? */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* the error is in the multistatus now. do not stop the traversal. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* if a collection, recursively copy/move it and its children,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * including the state dirs
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe params.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_HIDDEN;
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* params.walk_ctx is managed by dav_fs_internal_walk() */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* postfix is needed for MOVE to delete source dirs */
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* note that we return the error OR the multistatus. never both */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((err = dav_fs_internal_walk(¶ms, depth, is_move, dst,
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* on a "real" error, then just punt. nothing else to do. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* some multistatus responses exist. wrap them in a 207 */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(src->info->pool, HTTP_MULTI_STATUS, 0, 0,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Error(s) occurred on some resources during "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "the COPY/MOVE process.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* not a collection */
f4c310fd2555c6faca1f980f00b161eadb089023gstein if ((err = dav_fs_copymove_file(is_move, src->info->pool,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### push a higher-level description? */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* copy/move properties as well */
f4c310fd2555c6faca1f980f00b161eadb089023gstein return dav_fs_copymoveset(is_move, src->info->pool, src, dst, &work_buf);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### strictly speaking, this is a design error; we should not
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### have reached this point.
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(src->info->pool, HTTP_INTERNAL_SERVER_ERROR, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "DESIGN ERROR: a mix of repositories "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "was passed to copy_resource.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein if ((err = dav_fs_copymove_resource(0, src, dst, depth,
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* update state of destination resource to show it exists */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### strictly speaking, this is a design error; we should not
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### have reached this point.
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(src->info->pool, HTTP_INTERNAL_SERVER_ERROR, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "DESIGN ERROR: a mix of repositories "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "was passed to move_resource.");
490062b5568680531b35102c60228d1802fcdb23sf /* try rename first */
490062b5568680531b35102c60228d1802fcdb23sf rv = apr_file_rename(srcinfo->pathname, dstinfo->pathname, srcinfo->pool);
5646ba89a25a695006edae46de226fb57a2e6270gstein /* if we can't simply rename, then do it the hard way... */
5646ba89a25a695006edae46de226fb57a2e6270gstein if ((err = dav_fs_copymove_resource(1, src, dst, DAV_INFINITY,
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* update resource states */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* no multistatus response */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### should have a better error than this. */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(srcinfo->pool, HTTP_INTERNAL_SERVER_ERROR, 0, rv,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not rename resource.");
490062b5568680531b35102c60228d1802fcdb23sf /* Rename did work. Update resource states and move properties as well */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* no error. we're done. go ahead and return now. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* error occurred during properties move; try to put resource back */
066877f1a045103acfdd376d48cdd473c33f409bdougm if (apr_file_rename(dstinfo->pathname, srcinfo->pathname,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* couldn't put it back! */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The resource was moved, but a failure "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "occurred during the move of its "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "properties. The resource could not be "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "restored to its original location. The "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "server is now in an inconsistent state.",
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* update resource states again */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* resource moved back, but properties may be inconsistent */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The resource was moved, but a failure "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "occurred during the move of its properties. "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The resource was moved back to its original "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "location, but its properties may have been "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "partially moved. The server may be in an "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "inconsistent state.",
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gsteinstatic dav_error * dav_fs_delete_walker(dav_walk_resource *wres, int calltype)
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* do not attempt to remove a null resource,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * or a collection with children
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein (!wres->resource->collection || calltype == DAV_CALLTYPE_POSTFIX)) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* try to remove the resource */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** If an error occurred, then add it to multistatus response.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** Note that we add it for the root resource, too. It is quite
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** possible to delete the whole darn tree, yet fail on the root.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** (also: remember we are deleting via a postfix traversal)
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ### assume there is a permissions problem */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ### use errno to generate DAV:responsedescription? */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic dav_error * dav_fs_remove_resource(dav_resource *resource,
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* if a collection, recursively remove it and its children,
f4c310fd2555c6faca1f980f00b161eadb089023gstein * including the state dirs
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* on a "real" error, then just punt. nothing else to do. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* some multistatus responses exist. wrap them in a 207 */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(info->pool, HTTP_MULTI_STATUS, 0, 0,
f4c310fd2555c6faca1f980f00b161eadb089023gstein "Error(s) occurred on some resources during "
f4c310fd2555c6faca1f980f00b161eadb089023gstein "the deletion process.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* no errors... update resource state */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* not a collection; remove the file and its properties */
99d46a23c6eac800f327b29f8009f7d7da986230trawick if ((status = apr_file_remove(info->pathname, info->pool)) != APR_SUCCESS) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### put a description in here */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(info->pool, HTTP_FORBIDDEN, 0, status, NULL);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* update resource state */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* remove properties and return its result */
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* ### move this to dav_util? */
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* Walk recursively down through directories, *
f4c310fd2555c6faca1f980f00b161eadb089023gstein * including lock-null resources as we go. */
26250b0077972bf21b6d8a8d23772a4cf53f9477gsteinstatic dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth)
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ensure the context is prepared properly, then call the func */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* put a trailing slash onto the directory, in preparation for appending
f4c310fd2555c6faca1f980f00b161eadb089023gstein * files to it as we discovery them within the directory */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein dav_check_bufsize(pool, &fsctx->path1, DAV_BUFFER_PAD);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe fsctx->path1.buf[fsctx->path1.cur_len] = '\0'; /* in pad area */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* if a secondary path is present, then do that, too */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe dav_check_bufsize(pool, &fsctx->path2, DAV_BUFFER_PAD);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe fsctx->path2.buf[fsctx->path2.cur_len] = '\0'; /* in pad area */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* Note: the URI should ALREADY have a trailing "/" */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* for this first pass of files, all resources exist */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* a file is the default; we'll adjust if we hit a directory */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* open and scan the directory */
99d46a23c6eac800f327b29f8009f7d7da986230trawick if ((status = apr_dir_open(&dirp, fsctx->path1.buf, pool)) != APR_SUCCESS) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### need a better error */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(pool, HTTP_NOT_FOUND, 0, status, NULL);
ac65d432dabe462e98489f8e3946b2537ca9ecf6wrowe while ((apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp)) == APR_SUCCESS) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* avoid recursing into our current, parent, or state directories */
ac65d432dabe462e98489f8e3946b2537ca9ecf6wrowe && (len == 1 || (dirent.name[1] == '.' && len == 2))) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### need to authorize each file */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### example: .htaccess is normally configured to fail auth */
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf /* stuff in the state directory and temp files are never authorized! */
a6e4caaa97e433cc2ef78d957bc32756d9c49f79sf /* skip the state dir and temp files unless a HIDDEN is performed */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* append this file onto the path buffer (copy null term) */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe dav_buffer_place_mem(pool, &fsctx->path1, dirent.name, len + 1, 0);
e8f95a682820a599fe41b22977010636be5c2717jim status = apr_stat(&fsctx->info1.finfo, fsctx->path1.buf,
b6126f9c87296cf2cd10b0a39f7330a9d50e68d7gstein if (status != APR_SUCCESS && status != APR_INCOMPLETE) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* woah! where'd it go? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### should have a better error here */
99d46a23c6eac800f327b29f8009f7d7da986230trawick err = dav_new_error(pool, HTTP_NOT_FOUND, 0, status, NULL);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* copy the file to the URI, too. NOTE: we will pad an extra byte
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe for the trailing slash later. */
4f01ee597f569d80e2e81f912e425a572002328cbreser dav_buffer_place_mem(pool, &fsctx->uri_buf, dirent.name, len + 1, 1);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* if there is a secondary path, then do that, too */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe dav_buffer_place_mem(pool, &fsctx->path2, dirent.name, len + 1, 0);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* set up the (internal) pathnames for the two resources */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* set up the URI for the current resource */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### for now, only process regular files (e.g. skip symlinks) */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* call the function for the specified dir + file */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### maybe add a higher-level description? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* adjust length to incorporate the subdir name */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* adjust URI length to incorporate subdir and a slash */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* switch over to a collection */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* recurse on the subdir */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### don't always want to quit on error from single child */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((err = dav_fs_walker(fsctx, depth - 1)) != NULL) {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### maybe add a higher-level description? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* put the various information back */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* assert: res1.exists == 1 */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ### check the return value of this? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* null terminate the directory name */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* Include any lock null resources found in this collection */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ### maybe add a higher-level description? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* put a slash back on the end of the directory */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* these are all non-existant (files) */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe memset(&fsctx->info1.finfo, 0, sizeof(fsctx->info1.finfo));
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe apr_size_t len = strlen(fsctx->locknull_buf.buf + offset);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** Append the locknull file to the paths and the URI. Note that
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** we don't have to pad the URI for a slash since a locknull
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** resource is not a collection.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* set up the (internal) pathnames for the two resources */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* set up the URI for the current resource */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** To prevent a PROPFIND showing an expired locknull
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** resource, query the lock database to force removal
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** of both the lock entry and .locknull, if necessary..
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** Sure, the query in PROPFIND would do this.. after
e8f95a682820a599fe41b22977010636be5c2717jim ** the locknull resource was already included in the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** NOTE: we assume the caller has opened the lock database
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** if they have provided DAV_WALKTYPE_LOCKNULL.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### we should also look into opening it read-only and
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### eliding timed-out items from the walk, yet leaving
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### them in the locknull database until somebody opens
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### the thing writable.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### probably ought to use has_locks. note the problem
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### mentioned above, though... we would traverse this as
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### a locknull, but then a PROPFIND would load the lock
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### info, causing a timeout and the locks would not be
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### reported. Therefore, a null resource would be returned
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### in the PROPFIND.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### alternative: just load unresolved locks. any direct
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### locks will be timed out (correct). any indirect will
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### not (correct; consider if a parent timed out -- the
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### timeout routines do not walk and remove indirects;
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### even the resolve func would probably fail when it
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ### tried to find a timed-out direct lock).
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe if ((err = dav_lock_query(params->lockdb, &fsctx->res1,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### maybe add a higher-level description? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* call the function for the specified dir + file */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* ### maybe add a higher-level description? */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* reset the exists flag */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* replace the dirs' trailing slashes with null terms */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* this is a collection which exists */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe return (*params->func)(&fsctx->wres, DAV_CALLTYPE_POSTFIX);
707ecf9559338ec06b24334bc9abcca670325cc4gsteinstatic dav_error * dav_fs_internal_walk(const dav_walk_params *params,
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(params->pool, HTTP_INTERNAL_SERVER_ERROR, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "DESIGN ERROR: walker called to walk locknull "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "resources, but a lockdb was not provided.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* ### zero out versioned, working, baselined? */
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* the pathname is stored in the path1 buffer */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein dav_buffer_init(params->pool, &fsctx.path1, fsctx.info1.pathname);
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* internal call from the COPY/MOVE code. set it up. */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* res2 does not exist -- clear its finfo structure */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe memset(&fsctx.info2.finfo, 0, sizeof(fsctx.info2.finfo));
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* the pathname is stored in the path2 buffer */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe dav_buffer_init(params->pool, &fsctx.path2, fsctx.info2.pathname);
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein /* prep the URI buffer */
52c1d304b1bd8e05da40a7cded2ecb9f0ba614c5gstein dav_buffer_init(params->pool, &fsctx.uri_buf, params->root->uri);
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* if we have a directory, then ensure the URI has a trailing "/" */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe && fsctx.uri_buf.buf[fsctx.uri_buf.cur_len - 1] != '/') {
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* this will fall into the pad area */
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* the current resource's URI is stored in the uri_buf buffer */
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* point the callback's resource at our structure */
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* always return the error, and any/all multistatus responses */
f94aab38f6ee899f463f0118ea395291f7c5b4cegsteinstatic dav_error * dav_fs_walk(const dav_walk_params *params, int depth,
707ecf9559338ec06b24334bc9abcca670325cc4gstein /* always return the error, and any/all multistatus responses */
f94aab38f6ee899f463f0118ea395291f7c5b4cegstein return dav_fs_internal_walk(params, depth, 0, NULL, response);
f4c310fd2555c6faca1f980f00b161eadb089023gstein/* dav_fs_etag: Stolen from ap_make_etag. Creates a strong etag
f4c310fd2555c6faca1f980f00b161eadb089023gstein * for file path.
f4c310fd2555c6faca1f980f00b161eadb089023gstein * ### do we need to return weak tags sometimes?
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const char *dav_fs_getetag(const dav_resource *resource)
fec106c7688e279dfde4403bc3c935fec97c1d62sf /* XXX: This should really honor the FileETag setting */
0db981f8fdfb62c5149efa079f0369b73d472d04rpluem return apr_psprintf(ctx->pool, "\"%" APR_UINT64_T_HEX_FMT "-%"
0db981f8fdfb62c5149efa079f0369b73d472d04rpluem return apr_psprintf(ctx->pool, "\"%" APR_UINT64_T_HEX_FMT "\"",
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const dav_hooks_repository dav_hooks_repository_fs =
f4c310fd2555c6faca1f980f00b161eadb089023gstein DEBUG_GET_HANDLER, /* normally: special GET handling not required */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic dav_prop_insert dav_fs_insert_prop(const dav_resource *resource,
f4c310fd2555c6faca1f980f00b161eadb089023gstein const char *s;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* an HTTP-date can be 29 chars plus a null term */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* a 64-bit size can be 20 chars plus a null term */
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** None of FS provider properties are defined if the resource does not
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** exist. Just bail for this case.
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** Even though we state that the FS properties are not defined, the
956f4b1551215610a57f3b52822dbac6f41a8aa9gstein ** client cannot store dead values -- we deny that thru the is_writable
f4c310fd2555c6faca1f980f00b161eadb089023gstein ** hook function.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** Closest thing to a creation date. since we don't actually
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** perform the operations that would modify ctime (after we
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** create the file), then we should be pretty safe here.
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* our property, but not defined on collection resources */
dc52cac281d8b311dc47d115ed979f923b667679rjung apr_snprintf(buf, sizeof(buf), "%" APR_OFF_T_FMT, resource->info->finfo.size);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* our property, but not defined on collection resources */
f54da7877f9e092465df38bfda142f3e71dbb7aawrowe /* our property, but not defined on this platform */
f54da7877f9e092465df38bfda142f3e71dbb7aawrowe /* the files are "ours" so we only need to check owner exec privs */
5fbee309625f7a631a42d7dc05bbfa0d45a926ccgstein /* ### what the heck was this property? */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* assert: value != NULL */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein /* get the information and global NS index for the property */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein global_ns = dav_get_liveprop_info(propid, &dav_fs_liveprop_group, &info);
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein /* assert: info != NULL && info->name != NULL */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* DBG3("FS: inserting lp%d:%s (local %d)", ns, scan->name, scan->ns); */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein global_ns, info->name, value, global_ns, info->name);
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe s = apr_psprintf(p, "<lp%d:%s/>" DEBUG_CR, global_ns, info->name);
c7548bcd69fbe1338ad855ba44f0b2b774e57bd8gstein /* assert: what == DAV_PROP_INSERT_SUPPORTED */
bbba27074551817d7c6a606c4362965c26a0777egstein "<D:supported-live-property D:name=\"%s\" "
c7548bcd69fbe1338ad855ba44f0b2b774e57bd8gstein /* we inserted what was asked for */
956f4b1551215610a57f3b52822dbac6f41a8aa9gsteinstatic int dav_fs_is_writable(const dav_resource *resource, int propid)
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein /* if we have the executable property, and this isn't a collection,
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein then the property is writable. */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein if (propid == DAV_PROPID_FS_executable && !resource->collection)
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein (void) dav_get_liveprop_info(propid, &dav_fs_liveprop_group, &info);
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic dav_error *dav_fs_patch_validate(const dav_resource *resource,
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The 'executable' property cannot be removed.");
5646ba89a25a695006edae46de226fb57a2e6270gstein /* ### hmm. this isn't actually looking at all the possible text items */
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein /* DBG3("name=%s cdata=%s f_cdata=%s",elem->name,cdata ? cdata->text : "[null]",f_cdata ? f_cdata->text : "[null]"); */
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The 'executable' property expects a single "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "character, valued 'T' or 'F'. There was no "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "value submitted.");
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The 'executable' property expects a single "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "character, valued 'T' or 'F'. The value "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "submitted is invalid.");
99d46a23c6eac800f327b29f8009f7d7da986230trawick return dav_new_error(resource->info->pool, HTTP_CONFLICT, 0, 0,
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "The 'executable' property expects a single "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "character, valued 'T' or 'F'. The value submitted "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "has too many characters.");
bbba27074551817d7c6a606c4362965c26a0777egsteinstatic dav_error *dav_fs_patch_exec(const dav_resource *resource,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm apr_fileperms_t perms = resource->info->finfo.protection;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* assert: prop == executable. operation == SET. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* don't do anything if there is no change. no rollback info either. */
252e2478cb56afb5ca8585b50bc2ffb780d2efb6gstein /* DBG2("new value=%d (old=%d)", value, old_value); */
99d46a23c6eac800f327b29f8009f7d7da986230trawick if ((status = apr_file_perms_set(resource->info->pathname, perms))
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "Could not set the executable flag of the "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "target resource.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* update the resource and set up the rollback context */
bbba27074551817d7c6a606c4362965c26a0777egsteinstatic void dav_fs_patch_commit(const dav_resource *resource,
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* nothing to do */
bbba27074551817d7c6a606c4362965c26a0777egsteinstatic dav_error *dav_fs_patch_rollback(const dav_resource *resource,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm apr_fileperms_t perms = resource->info->finfo.protection & ~APR_UEXECUTE;
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* assert: prop == executable. operation == SET. */
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* restore the executable bit */
99d46a23c6eac800f327b29f8009f7d7da986230trawick if ((status = apr_file_perms_set(resource->info->pathname, perms))
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "After a failure occurred, the resource's "
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe "executable flag could not be restored.");
f4c310fd2555c6faca1f980f00b161eadb089023gstein /* restore the resource's state */
f4c310fd2555c6faca1f980f00b161eadb089023gsteinstatic const dav_hooks_liveprop dav_hooks_liveprop_fs =
acdb373d92c698a2ac260e03da95816c8a091eb6gsteinint dav_fs_find_liveprop(const dav_resource *resource,
acdb373d92c698a2ac260e03da95816c8a091eb6gstein /* don't try to find any liveprops if this isn't "our" resource */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein return dav_do_find_liveprop(ns_uri, name, &dav_fs_liveprop_group, hooks);
6b745319b1099edacf401e8911efa480440f999agsteinvoid dav_fs_insert_all_liveprops(request_rec *r, const dav_resource *resource,
acdb373d92c698a2ac260e03da95816c8a091eb6gstein /* don't insert any liveprops if this isn't "our" resource */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe /* a lock-null resource */
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### technically, we should insert empty properties. dunno offhand
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### what part of the spec said this, but it was essentially thus:
6f15570e3adc0faf87bf55f70857028276fc9e32wrowe ** ### "the properties should be defined, but may have no value".
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein (void) dav_fs_insert_prop(resource, DAV_PROPID_creationdate,
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein (void) dav_fs_insert_prop(resource, DAV_PROPID_getcontentlength,
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein (void) dav_fs_insert_prop(resource, DAV_PROPID_getlastmodified,
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein (void) dav_fs_insert_prop(resource, DAV_PROPID_getetag,
0b1895a2cd5b4a9450709abdb7ae9974908f9382gstein /* Only insert this property if it is defined for this platform. */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein (void) dav_fs_insert_prop(resource, DAV_PROPID_FS_executable,
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein /* ### we know the others aren't defined as liveprops */
5a47cad1aef57039cd47eb34ebbc2959c610f326gstein /* register the namespace URIs */
0e8fe062a6ec71b4207d1a125ee6b44b7fd30857gstein dav_register_liveprop_group(p, &dav_fs_liveprop_group);
5a47cad1aef57039cd47eb34ebbc2959c610f326gstein /* register the repository provider */
eb2abb2d3f87f28e99bcb282b91e432822b4d9b4gstein dav_register_provider(p, "filesystem", &dav_fs_provider);