util_lock.c revision f5ec9b038bb9db933072ba2c0a8e7bb2a3cedbda
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl/* ====================================================================
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * The Apache Software License, Version 1.1
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * Copyright (c) 2000 The Apache Software Foundation. All rights
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * Redistribution and use in source and binary forms, with or without
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * modification, are permitted provided that the following conditions
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * 1. Redistributions of source code must retain the above copyright
a530dde7009b0a808300c420def741354a4d13d2Martin Kühl * notice, this list of conditions and the following disclaimer.
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * 2. Redistributions in binary form must reproduce the above copyright
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * notice, this list of conditions and the following disclaimer in
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * the documentation and/or other materials provided with the
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * distribution.
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * 3. The end-user documentation included with the redistribution,
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * if any, must include the following acknowledgment:
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * "This product includes software developed by the
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * Apache Software Foundation (http://www.apache.org/)."
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * Alternately, this acknowledgment may appear in the software itself,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * if and wherever such third-party acknowledgments normally appear.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * 4. The names "Apache" and "Apache Software Foundation" must
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * not be used to endorse or promote products derived from this
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * software without prior written permission. For written
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * permission, please contact apache@apache.org.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * 5. Products derived from this software may not be called "Apache",
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco * nor may "Apache" appear in their name, without prior written
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * permission of the Apache Software Foundation.
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco * SUCH DAMAGE.
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco * ====================================================================
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * This software consists of voluntary contributions made by many
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco * individuals on behalf of the Apache Software Foundation. For more
d72e314a1952b4418fb1c98b17dbab0d16bba585Adrián Riesco * information on the Apache Software Foundation, please see
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** DAV repository-independent lock functions
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco/* ---------------------------------------------------------------
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** Property-related lock functions
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** dav_lock_get_activelock: Returns a <lockdiscovery> containing
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** an activelock element for every item in the lock_discovery tree
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescoconst char *dav_lock_get_activelock(request_rec *r, dav_lock *lock,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* If no locks or no lock provider, there are no locks */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** Since resourcediscovery is defined with (activelock)*,
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco ** <D:activelock/> shouldn't be necessary for an empty lock.
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco ** Note: it could be interesting to sum the lengths of the owners
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** and locktokens during this loop. However, the buffer
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** mechanism provides some rough padding so that we don't
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** really need to have an exact size. Further, constructing
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** locktoken strings could be relatively expensive.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco for (lock_scan = lock; lock_scan != NULL; lock_scan = lock_scan->next)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* if a buffer was not provided, then use an internal buffer */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* reset the length before we start appending stuff */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* prep the buffer with a "good" size */
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco if (lock->rectype == DAV_LOCKREC_INDIRECT_PARTIAL) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### crap. design error */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "DESIGN ERROR: attempted to product an "
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "activelock element from a partial, indirect "
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "lock record. Creating an XML parsing error "
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "to ease detection of this situation: <");
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco dav_buffer_append(p, pbuf, "<D:activelock>" DEBUG_CR "<D:locktype>");
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### internal error. log something? */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco dav_buffer_append(p, pbuf, "</D:locktype>" DEBUG_CR "<D:lockscope>");
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### internal error. log something? */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco dav_buffer_append(p, pbuf, "</D:lockscope>" DEBUG_CR);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco sprintf(tmp, "<D:depth>%s</D:depth>" DEBUG_CR,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco lock->depth == DAV_INFINITY ? "infinity" : "0");
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** This contains a complete, self-contained <DAV:owner> element,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** with namespace declarations and xml:lang handling. Just drop
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco sprintf(tmp, "Second-%lu", lock->timeout - now);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco (*hooks->format_locktoken)(p, lock->locktoken));
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco** dav_lock_parse_lockinfo: Validates the given xml_doc to contain a
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco** lockinfo XML element, then populates a dav_lock structure
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco** with its contents.
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescodav_error * dav_lock_parse_lockinfo(request_rec *r,
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "The request body contains an unexpected "
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco "XML root element.");
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco if ((err = (*hooks->create_lock)(lockdb, resource, &lock)) != NULL) {
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco "Could not parse the lockinfo due to an "
8b389272b3312c6d3e3c0aee2e94bca6dbdade50Adrián Riesco "internal problem creating a lock structure.",
8b389272b3312c6d3e3c0aee2e94bca6dbdade50Adrián Riesco "An invalid Depth header was specified.");
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco /* Parse elements in the XML body */
8b389272b3312c6d3e3c0aee2e94bca6dbdade50Adrián Riesco for (child = doc->root->first_child; child; child = child->next) {
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco if (strcmp(child->first_child->name, "write") == 0) {
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco if (strcmp(child->first_child->name, "exclusive") == 0)
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco else if (strcmp(child->first_child->name, "shared") == 0)
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco if (strcmp(child->name, "owner") == 0 && lock->owner == NULL) {
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco /* quote all the values in the <DAV:owner> element */
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco ** Store a full <DAV:owner> element with namespace definitions
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco ** and an xml:lang definition, if applicable.
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco dav_xml2text(p, child, DAV_X2T_FULL_NS_LANG, doc->namespaces, NULL,
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco return dav_new_error(p, HTTP_PRECONDITION_FAILED, 0,
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco "The server cannot satisfy the "
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco "LOCK request due to an unknown XML "
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco "element (\"%s\") within the "
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco "DAV:lockinfo element.",
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco/* ---------------------------------------------------------------
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco** General lock functions
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riesco/* dav_lock_walker: Walker callback function to record indirect locks */
6b2e3d60f2e2c230c9637bf0701d7024d289764dAdrián Riescostatic dav_error * dav_lock_walker(dav_walker_ctx *ctx, int calltype)
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco /* We don't want to set indirects on the target */
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco if ((*ctx->resource->hooks->is_same_resource)(ctx->resource, ctx->root))
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco if ((err = (*ctx->lockdb->hooks->append_locks)(ctx->lockdb, ctx->resource,
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco /* ### add a higher-level description? */
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco /* add to the multistatus response */
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco dav_add_response(ctx, ctx->resource->uri, err->status, NULL);
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco ** ### actually, this is probably wrong: we want to fail the whole
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco ** ### LOCK process if something goes bad. maybe the caller should
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco ** ### do a dav_unlock() (e.g. a rollback) if any errors occurred.
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco** dav_add_lock: Add a direct lock for resource, and indirect locks for
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco** all children, bounded by depth.
0be63c5d4b5e66cc600a0003081ae2bf85be9615Adrián Riesco** ### assume request only contains one lock
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riescodav_error * dav_add_lock(request_rec *r, const dav_resource *resource,
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco /* Requested lock can be:
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco * Depth: 0 for null resource, existing resource, or existing collection
fe5611d78ea0648e8719cb004a6a26e9a033429aAdrián Riesco * Depth: Inf for existing collection
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco ** 2518 9.2 says to ignore depth if target is not a collection (it has
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco ** no internal children); pretend the client gave the correct depth.
b9840e4ee6fda6e42fa4ee9f337482ccc4839a39Adrián Riesco /* In all cases, first add direct entry in lockdb */
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco ** Append the new (direct) lock to the resource's existing locks.
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco ** Note: this also handles locknull resources
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco if ((err = (*hooks->append_locks)(lockdb, resource, 0, lock)) != NULL) {
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco /* ### maybe add a higher-level description */
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco /* Walk existing collection and set indirect locks */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco ctx.walk_type = DAV_WALKTYPE_ALL | DAV_WALKTYPE_AUTH;
223be434693e8c97e2522ac19155a284b3536035Adrián Riesco dav_buffer_init(r->pool, &ctx.uri, resource->uri);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco err = (*resource->hooks->walk)(&ctx, DAV_INFINITY);
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* implies a 5xx status code occurred. screw the multistatus */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* manufacture a 207 error for the multistatus response */
7fc57d0f02d0fec1192376ccebe2be0224cb9a55Adrián Riesco return dav_new_error(r->pool, HTTP_MULTI_STATUS, 0,
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco "Error(s) occurred on resources during the "
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco "addition of a depth lock.");
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco** dav_lock_query: Opens the lock database. Returns a linked list of
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco** dav_lock structures for all direct locks on path.
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescodav_error * dav_lock_query(dav_lockdb *lockdb, const dav_resource *resource,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* If no lock database, return empty result */
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco /* ### insert a higher-level description? */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco return (*lockdb->hooks->get_locks)(lockdb, resource,
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco/* dav_unlock_walker: Walker callback function to remove indirect locks */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riescostatic dav_error * dav_unlock_walker(dav_walker_ctx *ctx, int calltype)
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco if ((err = (*ctx->lockdb->hooks->remove_lock)(ctx->lockdb, ctx->resource,
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* ### should we stop or return a multistatus? looks like STOP */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* ### add a higher-level description? */
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco** dav_get_direct_resource:
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco** Find a lock on the specified resource, then return the resource the
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco** lock was applied to (in other words, given a (possibly) indirect lock,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco** return the direct lock's corresponding resource).
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco** If the lock is an indirect lock, this usually means traversing up the
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco** namespace [repository] hierarchy. Note that some lock providers may be
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco** able to return this information with a traversal.
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riescostatic dav_error * dav_get_direct_resource(ap_pool_t *p,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco return (*lockdb->hooks->lookup_resource)(lockdb, locktoken,
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco /* Find the top of this lock-
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * If r->filename's direct locks include locktoken, use r->filename.
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco * If r->filename's indirect locks include locktoken, retry r->filename/..
aea9000fc94442cbfc92596f4264473c0fce51e4Adrián Riesco ** Find the lock specified by <locktoken> on <resource>. If it is
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** an indirect lock, then partial results are okay. We're just
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco ** trying to find the thing and know whether it is a direct or
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco ** an indirect lock.
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco if ((err = (*lockdb->hooks->find_lock)(lockdb, resource, locktoken,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### add a higher-level desc? */
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco /* not found! that's an error. */
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco "The specified locktoken does not correspond "
c1cf2f634a37116ff90e99ca710179a23115cbfbAdrián Riesco "to an existing lock on this resource.");
71410be62420b321abb02ef1ac2b7f2141b3bc7fAdrián Riesco /* we found the direct lock. return this resource. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* the lock was indirect. move up a level in the URL namespace */
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco resource = (*resource->hooks->get_parent_resource)(resource);
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco "The lock database is corrupt. A direct lock could "
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco "not be found for the corresponding indirect lock "
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "on this resource.");
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco** dav_unlock: Removes all direct and indirect locks for r->filename,
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco** with given locktoken. If locktoken == null_locktoken, all locks
6d498b6f56ed9f71cced898b6c42fb48f6e60583Adrián Riesco** are removed. If r->filename represents an indirect lock,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** we must unlock the appropriate direct lock.
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco** Returns OK or appropriate HTTP_* response and logs any errors.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** ### We've already crawled the tree to ensure everything was locked
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco** by us; there should be no need to incorporate a rollback.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescoint dav_unlock(request_rec *r, const dav_resource *resource,
172f4dfb4b858440fab545bac00d3ec4abd0cbe4Adrián Riesco const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
172f4dfb4b858440fab545bac00d3ec4abd0cbe4Adrián Riesco const dav_hooks_repository *repos_hooks = resource->hooks;
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* If no locks provider, we shouldn't have been called */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### map result to something nice; log an error */
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* 2518 requires the entire lock to be removed if resource/locktoken
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * point to an indirect lock. We need resource of the _direct_
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * lock in order to walk down the tree and remove the locks. So,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * If locktoken != null_locktoken,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Walk up the resource hierarchy until we see a direct lock.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Or, we could get the direct lock's db/key, pick out the URL
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco * and do a subrequest. I think walking up is faster and will work
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * all the time.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * Just start removing all locks at and below resource.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if ((err = (*hooks->open_lockdb)(r, 0, 1, &lockdb)) != NULL) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### return err! maybe add a higher-level desc */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### map result to something nice; log an error */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco && (err = dav_get_direct_resource(r->pool, lockdb,
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* ### add a higher-level desc? */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### should return err! */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* At this point, lock_resource/locktoken refers to a direct lock (key), ie
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco * the root of a depth > 0 lock, or locktoken is null.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if ((err = (*hooks->remove_lock)(lockdb, lock_resource,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### add a higher-level desc? */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### return err! */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ctx.walk_type = DAV_WALKTYPE_ALL | DAV_WALKTYPE_LOCKNULL;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco dav_buffer_init(r->pool, &ctx.uri, lock_resource->uri);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco err = (*repos_hooks->walk)(&ctx, DAV_INFINITY);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### fix this! */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* dav_inherit_walker: Walker callback function to inherit locks */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic dav_error * dav_inherit_walker(dav_walker_ctx *ctx, int calltype)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco && (*ctx->resource->hooks->is_same_resource)(ctx->resource,
6f6549c13f912de12345850e4eb248ec358c1b43Adrián Riesco /* ### maybe add a higher-level desc */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return (*ctx->lockdb->hooks->append_locks)(ctx->lockdb, ctx->resource, 1,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** dav_inherit_locks: When a resource or collection is added to a collection,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** locks on the collection should be inherited to the resource/collection.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** (MOVE, MKCOL, etc) Here we propagate any direct or indirect locks from
172f4dfb4b858440fab545bac00d3ec4abd0cbe4Adrián Riesco** parent of resource to resource and below.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescostatic dav_error * dav_inherit_locks(request_rec *r, dav_lockdb *lockdb,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco const dav_hooks_repository *repos_hooks = resource->hooks;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco which_resource = (*repos_hooks->get_parent_resource)(resource);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### map result to something nice; log an error */
3b1e33dd8d2de8301d7a31860dd1819bd3752718Adrián Riesco return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "Could not fetch parent resource. Unable to "
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "inherit locks from the parent and apply "
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco "them to this resource.");
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if ((err = (*lockdb->hooks->get_locks)(lockdb, which_resource,
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco /* ### maybe add a higher-level desc */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* No locks to propagate, just return */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** (1) Copy all indirect locks from our parent;
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco ** (2) Create indirect locks for the depth infinity, direct locks
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco ** in our parent.
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco ** The append_locks call in the walker callback will do the indirect
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco ** conversion, but we need to remove any direct locks that are NOT
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco ** depth "infinity".
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* <locks> has all our new locks. Walk down and propagate them. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ctx.walk_type = DAV_WALKTYPE_ALL | DAV_WALKTYPE_LOCKNULL;
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco dav_buffer_init(r->pool, &ctx.uri, resource->uri);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco return (*repos_hooks->walk)(&ctx, DAV_INFINITY);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco/* ---------------------------------------------------------------
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** Functions dealing with lock-null resources
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** dav_get_resource_state: Returns the state of the resource
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** r->filename: DAV_RESOURCE_NULL, DAV_RESOURCE_LOCK_NULL,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** or DAV_RESOURCE_EXIST.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco** Returns DAV_RESOURCE_ERROR if an error occurs.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riescoint dav_get_resource_state(request_rec *r, const dav_resource *resource)
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** A locknull resource has the form:
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** known-dir "/" locknull-file
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** It would be nice to look into <resource> to verify this form,
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** but it does not have enough information for us. Instead, we
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco ** can look at the path_info. If the form does not match, then
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco ** there is no way we could have a locknull resource -- it must
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco ** be a plain, null resource.
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco ** Apache sets r->filename to known-dir/unknown-file and r->path_info
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco ** to "" for the "proper" case. If anything is in path_info, then
fecce42517d20490f893c4a9dee29b000e1653eaAdrián Riesco ** it can't be a locknull resource.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** ### I bet this path_info hack doesn't work for repositories.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** ### Need input from repository implementors! What kind of
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** ### restructure do we need? New provider APIs?
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if (r->path_info != NULL && *r->path_info != '\0') {
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco if ((err = (*hooks->open_lockdb)(r, 1, 1, &lockdb)) == NULL) {
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco /* note that we might see some expired locks... *shrug* */
0f77efdcc159eee5682aabf2b9a3c178c467b466Adrián Riesco err = (*hooks->has_locks)(lockdb, resource, &locks_present);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### don't log an error. return err. add higher-level desc. */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ap_log_rerror(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, r,
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco "Failed to query lock-null status for %s",
7474965b2e6323002c96c0b39a59843cde201870Adrián Riesco if (resource_state == DAV_RESOURCE_LOCK_NULL) {
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco ** The resource is no longer a locknull resource. This will remove
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** the special marker.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** Note that a locknull resource has already inherited all of the
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** locks from the parent. We do not need to call dav_inherit_locks.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** NOTE: some lock providers record locks for locknull resources using
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** a different key than for regular resources. this will shift
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** the lock information between the two key types.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco (void)(*lockdb->hooks->remove_locknull_state)(lockdb, resource);
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** There are resources under this one, which are new. We must
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco ** propagate the locks down to the new resources.
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco (err = dav_inherit_locks(r, lockdb, resource, 0)) != NULL) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### add a higher level desc? */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco else if (resource_state == DAV_RESOURCE_NULL) {
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco /* ### should pass depth to dav_inherit_locks so that it can
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco ** ### optimize for the depth==0 case.
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* this resource should inherit locks from its parent */
5318901bb69bf247e0f341312c800ba4ea87e46bAdrián Riesco if ((err = dav_inherit_locks(r, lockdb, resource, 1)) != NULL) {
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco "The resource was created successfully, but "
51c15129e8118fed5c33c334f8df82619ce98e7dAdrián Riesco "there was a problem inheriting locks from "
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco "the parent resource.",
27aad79faa0eec8d0e7dda32bca710db95bd2d0aAdrián Riesco /* else the resource already exists and its locks are correct. */