af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder/* Licensed to the Apache Software Foundation (ASF) under one or more
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * contributor license agreements. See the NOTICE file distributed with
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * this work for additional information regarding copyright ownership.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * The ASF licenses this file to You under the Apache License, Version 2.0
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * (the "License"); you may not use this file except in compliance with
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * the License. You may obtain a copy of the License at
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * http://www.apache.org/licenses/LICENSE-2.0
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * Unless required by applicable law or agreed to in writing, software
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * distributed under the License is distributed on an "AS IS" BASIS,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * See the License for the specific language governing permissions and
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * limitations under the License.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * Generic DAV lock implementation that a DAV provider can use.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder/* ---------------------------------------------------------------
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * Lock database primitives
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * LOCK DATABASES
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * Lockdiscovery information is stored in the single lock database specified
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * by the DAVGenericLockDB directive. Information about this db is stored in
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * the per-dir configuration.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * The database is keyed by a key_type unsigned char (DAV_TYPE_FNAME)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * followed by full path.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * The value consists of a list of elements.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * DIRECT LOCK: [char (DAV_LOCK_DIRECT),
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * char (dav_lock_scope),
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * char (dav_lock_type),
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * time_t expires,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * apr_uuid_t locktoken,
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * char[] owner,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * char[] auth_user]
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * INDIRECT LOCK: [char (DAV_LOCK_INDIRECT),
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * apr_uuid_t locktoken,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * time_t expires,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * int key_size,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * char[] key]
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * The key is to the collection lock that resulted in this indirect lock
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder/* Stored lock_discovery prefix */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder/* Use the opaquelock scheme for locktokens */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder memcmp(&(plt1)->uuid, &(plt2)->uuid, sizeof((plt1)->uuid))
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder/* #################################################################
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * ### keep these structures (internal) or move fully to dav_lock?
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * We need to reliably size the fixed-length portion of
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * dav_lock_discovery; best to separate it into another
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * struct for a convenient sizeof, unless we pack lock_discovery.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder const char *owner; /* owner field from activelock */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder const char *auth_user; /* authenticated user who created the lock */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder/* Indirect locks represent locks inherited from containing collections.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * They reference the lock token for the collection the lock is
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * inherited from. A lock provider may also define a key to the
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * inherited lock, for fast datbase lookup. The key is opaque outside
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * the lock provider.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder/* ################################################################# */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * Stored direct lock info - full lock_discovery length:
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * prefix + Fixed length + lock token + 2 strings + 2 nulls (one for each
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder#define dav_size_direct(a) (1 + sizeof(dav_lock_discovery_fixed) \
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder + ((a)->auth_user ? strlen((a)->auth_user) : 0) \
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder/* Stored indirect lock info - lock token and apr_datum_t */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder#define dav_size_indirect(a) (1 + sizeof(apr_uuid_t) \
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder * The lockdb structure.
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder * The <db> field may be NULL, meaning one of two things:
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * 1) That we have not actually opened the underlying database (yet). The
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * <opened> field should be false.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * 2) We opened it readonly and it wasn't present.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * The delayed opening (determined by <opened>) makes creating a lockdb
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * quick, while deferring the underlying I/O until it is actually required.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * We export the notion of a lockdb, but hide the details of it. Most
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * implementations will use a database of some kind, but it is certainly
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * possible that alternatives could be used.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder request_rec *r; /* for accessing the uuid state */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder const char *lockdb_path; /* where is the lock database? */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder apr_dbm_t *db; /* if non-NULL, the lock database */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maedertypedef struct
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * The private part of the lock structure.
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder apr_datum_t key; /* key into the lock database */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maedertypedef struct
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder * This must be forward-declared so the open_lockdb function can use it.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederextern const dav_hooks_locks dav_hooks_locks_generic;
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederstatic dav_error * dav_generic_dbm_new_error(apr_dbm_t *db, apr_pool_t *p,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder /* There might not be a <db> if we had problems creating it. */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder errstr = "Could not open property database.";
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder (void) apr_dbm_geterror(db, &errcode, errbuf, sizeof(errbuf));
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, errcode, status, errstr);
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder/* internal function for creating locks */
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederstatic dav_lock *dav_generic_alloc_lock(dav_lockdb *lockdb, apr_datum_t key,
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder comb = apr_pcalloc(lockdb->info->pool, sizeof(*comb));
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * dav_generic_parse_locktoken
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * Parse an opaquelocktoken URI into a locktoken.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederstatic dav_error * dav_generic_parse_locktoken(apr_pool_t *p,
96de7ec4008f75574077816c4c71a22e6afe1e01Christian Maeder if (ap_strstr_c(char_token, "opaquelocktoken:") != char_token) {
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder HTTP_BAD_REQUEST, DAV_ERR_LOCK_UNK_STATE_TOKEN, 0,
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder "The lock token uses an unknown State-token "
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder "format and could not be parsed.");
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder locktoken = apr_pcalloc(p, sizeof(*locktoken));
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder if (apr_uuid_parse(&locktoken->uuid, char_token)) {
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder return dav_new_error(p, HTTP_BAD_REQUEST, DAV_ERR_LOCK_PARSE_TOKEN, 0,
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder "The opaquelocktoken has an incorrect format "
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder "and could not be parsed.");
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder * dav_generic_format_locktoken
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * Generate the URI for a locktoken
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maederstatic const char *dav_generic_format_locktoken(apr_pool_t *p,
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder return apr_pstrcat(p, "opaquelocktoken:", buf, NULL);
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * dav_generic_compare_locktoken
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * Determine whether two locktokens are the same
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maederstatic int dav_generic_compare_locktoken(const dav_locktoken *lt1,
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * dav_generic_really_open_lockdb:
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder * If the database hasn't been opened yet, then open the thing.
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maederstatic dav_error * dav_generic_really_open_lockdb(dav_lockdb *lockdb)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder status = apr_dbm_open(&lockdb->info->db, lockdb->info->lockdb_path,
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder lockdb->ro ? APR_DBM_READONLY : APR_DBM_RWCREATE,
96de7ec4008f75574077816c4c71a22e6afe1e01Christian Maeder err = dav_generic_dbm_new_error(lockdb->info->db, lockdb->info->pool,
status);
err);
return NULL;
if (force) {
return NULL;
return key;
#if DAV_DEBUG
HTTP_INTERNAL_SERVER_ERROR, 0, 0,
return err;
return NULL;
while(dp) {
while(ip) {
while(dp) {
while(ip) {
status);
err);
return NULL;
int add_method,
return err;
return NULL;
return NULL;
case DAV_LOCK_DIRECT:
++offset;
++offset;
case DAV_LOCK_INDIRECT:
--offset;
return dav_new_error(p,
apr_psprintf(p,
return NULL;
return err;
return NULL;
return supported;
return NULL;
return NULL;
int calltype,
#if DAV_DEBUG
HTTP_INTERNAL_SERVER_ERROR, 0, 0,
return err;
return err;
return NULL;
int partial_ok,
return err;
return NULL;
if (partial_ok) {
return err;
return NULL;
return NULL;
int *locks_present)
*locks_present = 0;
return err;
return NULL;
return NULL;
int make_indirect,
return err;
if (make_indirect) {
return err;
return NULL;
return err;
if (dprev)
if (iprev)
return err;
return NULL;
return dirty;
return err;
if (dirty
return err;
return err;
return err;
return NULL;