Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Apache/modules/dav/lock/   (Apache Software Stiftung Version 2.4.65©)  Datei vom 4.2.2022 mit Größe 38 kB image not shown  

SSL locks.c   Sprache: C

 
/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


/*
 * Generic DAV lock implementation that a DAV provider can use.
 */


#include "apr.h"
#include "apr_strings.h"
#include "apr_file_io.h"
#include "apr_uuid.h"

#define APR_WANT_MEMFUNC
#include "apr_want.h"

#include "apr_version.h"
#if !APR_VERSION_AT_LEAST(2,0,0)
#include "apu_version.h"
#endif

#include "httpd.h"
#include "http_log.h"
#include "http_main.h"      /* for ap_server_conf */

#include "mod_dav.h"

#include "locks.h"


/* ---------------------------------------------------------------
 *
 * Lock database primitives
 *
 */


/*
 * LOCK DATABASES
 *
 * Lockdiscovery information is stored in the single lock database specified
 * by the DAVGenericLockDB directive.  Information about this db is stored in
 * the per-dir configuration.
 *
 * KEY
 *
 * The database is keyed by a key_type unsigned char (DAV_TYPE_FNAME)
 * followed by full path.
 *
 * VALUE
 *
 * The value consists of a list of elements.
 *    DIRECT LOCK:     [char      (DAV_LOCK_DIRECT),
 *                      char      (dav_lock_scope),
 *                      char      (dav_lock_type),
 *                      int        depth,
 *                      time_t     expires,
 *                      apr_uuid_t locktoken,
 *                      char[]     owner,
 *                      char[]     auth_user]
 *
 *    INDIRECT LOCK:   [char      (DAV_LOCK_INDIRECT),
 *                      apr_uuid_t locktoken,
 *                      time_t     expires,
 *                      int        key_size,
 *                      char[]     key]
 *       The key is to the collection lock that resulted in this indirect lock
 */


#define DAV_TRUE                    1
#define DAV_FALSE                   0

#define DAV_CREATE_LIST            23
#define DAV_APPEND_LIST            24

/* Stored lock_discovery prefix */
#define DAV_LOCK_DIRECT             1
#define DAV_LOCK_INDIRECT           2

#define DAV_TYPE_FNAME             11

/* Use the opaquelock scheme for locktokens */
struct dav_locktoken {
    apr_uuid_t uuid;
};
#define dav_compare_locktoken(plt1, plt2) \
                memcmp(&(plt1)->uuid, &(plt2)->uuid, sizeof((plt1)->uuid))


/* #################################################################
 * ### keep these structures (internal) or move fully to dav_lock?
 */


/*
 * We need to reliably size the fixed-length portion of
 * dav_lock_discovery; best to separate it into another
 * struct for a convenient sizeof, unless we pack lock_discovery.
 */

typedef struct dav_lock_discovery_fixed
{
    char scope;
    char type;
    int depth;
    time_t timeout;
} dav_lock_discovery_fixed;

typedef struct dav_lock_discovery
{
    struct dav_lock_discovery_fixed f;

    dav_locktoken *locktoken;
    const char *owner;     /* owner field from activelock */
    const char *auth_user; /* authenticated user who created the lock */
    struct dav_lock_discovery *next;
} dav_lock_discovery;

/* Indirect locks represent locks inherited from containing collections.
 * They reference the lock token for the collection the lock is
 * inherited from. A lock provider may also define a key to the
 * inherited lock, for fast datbase lookup. The key is opaque outside
 * the lock provider.
 */

typedef struct dav_lock_indirect
{
    dav_locktoken *locktoken;
    apr_datum_t key;
    struct dav_lock_indirect *next;
    time_t timeout;
} dav_lock_indirect;

/* ################################################################# */

/*
 * Stored direct lock info - full lock_discovery length:
 * prefix + Fixed length + lock token + 2 strings + 2 nulls (one for each
 * string)
 */

#define dav_size_direct(a)  (1 + sizeof(dav_lock_discovery_fixed) \
                               + sizeof(apr_uuid_t) \
                               + ((a)->owner ? strlen((a)->owner) : 0) \
                               + ((a)->auth_user ? strlen((a)->auth_user) : 0) \
                               + 2)

/* Stored indirect lock info - lock token and apr_datum_t */
#define dav_size_indirect(a) (1 + sizeof(apr_uuid_t) \
                                + sizeof(time_t) \
                                + sizeof(int) + (a)->key.dsize)

/*
 * The lockdb structure.
 *
 * The <db> field may be NULL, meaning one of two things:
 * 1) That we have not actually opened the underlying database (yet). The
 *    <opened> field should be false.
 * 2) We opened it readonly and it wasn't present.
 *
 * The delayed opening (determined by <opened>) makes creating a lockdb
 * quick, while deferring the underlying I/O until it is actually required.
 *
 * We export the notion of a lockdb, but hide the details of it. Most
 * implementations will use a database of some kind, but it is certainly
 * possible that alternatives could be used.
 */

struct dav_lockdb_private
{
    request_rec *r; /* for accessing the uuid state */
    apr_pool_t *pool; /* a pool to use */
    const char *lockdb_path; /* where is the lock database? */

    int opened; /* we opened the database */
    apr_dbm_t *db; /* if non-NULL, the lock database */
};

typedef struct
{
    dav_lockdb pub;
    dav_lockdb_private priv;
} dav_lockdb_combined;

/*
 * The private part of the lock structure.
 */

struct dav_lock_private
{
    apr_datum_t key;        /* key into the lock database */
};
typedef struct
{
    dav_lock pub;
    dav_lock_private priv;
    dav_locktoken token;
} dav_lock_combined;

/*
 * This must be forward-declared so the open_lockdb function can use it.
 */

extern const dav_hooks_locks dav_hooks_locks_generic;

static dav_error * dav_generic_dbm_new_error(apr_dbm_t *db, apr_pool_t *p,
                                             apr_status_t status)
{
    int errcode;
    const char *errstr;
    dav_error *err;
    char errbuf[200];

    if (status == APR_SUCCESS) {
        return NULL;
    }

    /* There might not be a <db> if we had problems creating it. */
    if (db == NULL) {
        errcode = 1;
        errstr = "Could not open property database.";
    }
    else {
        (void) apr_dbm_geterror(db, &errcode, errbuf, sizeof(errbuf));
        errstr = apr_pstrdup(p, errbuf);
    }

    err = dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, errcode, status, errstr);
    return err;
}

/* internal function for creating locks */
static dav_lock *dav_generic_alloc_lock(dav_lockdb *lockdb, apr_datum_t key,
                                        const dav_locktoken *locktoken)
{
    dav_lock_combined *comb;

    comb = apr_pcalloc(lockdb->info->pool, sizeof(*comb));
    comb->pub.rectype = DAV_LOCKREC_DIRECT;
    comb->pub.info = &comb->priv;
    comb->priv.key = key;

    if (locktoken == NULL) {
        comb->pub.locktoken = &comb->token;
        apr_uuid_get(&comb->token.uuid);
    }
    else {
        comb->pub.locktoken = locktoken;
    }

    return &comb->pub;
}

/*
 * dav_generic_parse_locktoken
 *
 * Parse an opaquelocktoken URI into a locktoken.
 */

static dav_error * dav_generic_parse_locktoken(apr_pool_t *p,
                                               const char *char_token,
                                               dav_locktoken **locktoken_p)
{
    dav_locktoken *locktoken;

    if (ap_strstr_c(char_token, "opaquelocktoken:") != char_token) {
        return dav_new_error(p,
                             HTTP_BAD_REQUEST, DAV_ERR_LOCK_UNK_STATE_TOKEN, 0,
                             "The lock token uses an unknown State-token "
                             "format and could not be parsed.");
    }
    char_token += 16;

    locktoken = apr_pcalloc(p, sizeof(*locktoken));
    if (apr_uuid_parse(&locktoken->uuid, char_token)) {
        return dav_new_error(p, HTTP_BAD_REQUEST, DAV_ERR_LOCK_PARSE_TOKEN, 0,
                             "The opaquelocktoken has an incorrect format "
                             "and could not be parsed.");
    }

    *locktoken_p = locktoken;
    return NULL;
}

/*
 * dav_generic_format_locktoken
 *
 * Generate the URI for a locktoken
 */

static const char *dav_generic_format_locktoken(apr_pool_t *p,
                                                const dav_locktoken *locktoken)
{
    char buf[APR_UUID_FORMATTED_LENGTH + 1];

    apr_uuid_format(buf, &locktoken->uuid);
    return apr_pstrcat(p, "opaquelocktoken:", buf, NULL);
}

/*
 * dav_generic_compare_locktoken
 *
 * Determine whether two locktokens are the same
 */

static int dav_generic_compare_locktoken(const dav_locktoken *lt1,
                                         const dav_locktoken *lt2)
{
    return dav_compare_locktoken(lt1, lt2);
}

/*
 * dav_generic_really_open_lockdb:
 *
 * If the database hasn't been opened yet, then open the thing.
 */

static dav_error * dav_generic_really_open_lockdb(dav_lockdb *lockdb)
{
#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7)
    const apr_dbm_driver_t *driver;
    const apu_err_t *er;
#endif
    dav_error *err;
    apr_status_t status = APR_SUCCESS;

    if (lockdb->info->opened) {
        return NULL;
    }

#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7)
    status = apr_dbm_get_driver(&driver, NULL, &er, lockdb->info->pool);

    if (status) {
        ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf, APLOGNO(10288)
                     "mod_dav_lock: The DBM library '%s' could not be loaded: %s",
                             er->reason, er->msg);
        return dav_new_error(lockdb->info->pool, HTTP_INTERNAL_SERVER_ERROR, 1,
                status, "Could not load library for property database.");
    }

    status = apr_dbm_open2(&lockdb->info->db, driver, lockdb->info->lockdb_path,
                          lockdb->ro ? APR_DBM_READONLY : APR_DBM_RWCREATE,
                          APR_OS_DEFAULT, lockdb->info->pool);
#else
    status = apr_dbm_open(&lockdb->info->db, lockdb->info->lockdb_path,
                          lockdb->ro ? APR_DBM_READONLY : APR_DBM_RWCREATE,
                          APR_OS_DEFAULT, lockdb->info->pool);
#endif

    if (status) {
        err = dav_generic_dbm_new_error(lockdb->info->db, lockdb->info->pool,
                                        status);
        return dav_push_error(lockdb->info->pool,
                              HTTP_INTERNAL_SERVER_ERROR,
                              DAV_ERR_LOCK_OPENDB,
                              "Could not open the lock database.",
                              err);
    }

    /* all right. it is opened now. */
    lockdb->info->opened = 1;

    return NULL;
}

/*
 * dav_generic_open_lockdb:
 *
 * "open" the lock database, as specified in the global server configuration.
 * If force is TRUE, then the database is opened now, rather than lazily.
 *
 * Note that only one can be open read/write.
 */

static dav_error * dav_generic_open_lockdb(request_rec *r, int ro, int force,
                                           dav_lockdb **lockdb)
{
    dav_lockdb_combined *comb;

    comb = apr_pcalloc(r->pool, sizeof(*comb));
    comb->pub.hooks = &dav_hooks_locks_generic;
    comb->pub.ro = ro;
    comb->pub.info = &comb->priv;
    comb->priv.r = r;
    comb->priv.pool = r->pool;

    comb->priv.lockdb_path = dav_generic_get_lockdb_path(r);
    if (comb->priv.lockdb_path == NULL) {
        return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
                             DAV_ERR_LOCK_NO_DB, 0,
                             "A lock database was not specified with the "
                             "DAVGenericLockDB directive. One must be "
                             "specified to use the locking functionality.");
    }

    /* done initializing. return it. */
    *lockdb = &comb->pub;

    if (force) {
        /* ### add a higher-level comment? */
        return dav_generic_really_open_lockdb(*lockdb);
    }

    return NULL;
}

/*
 * dav_generic_close_lockdb:
 *
 * Close it. Duh.
 */

static void dav_generic_close_lockdb(dav_lockdb *lockdb)
{
    if (lockdb->info->db != NULL) {
        apr_dbm_close(lockdb->info->db);
    }
    lockdb->info->opened = 0;
}

/*
 * dav_generic_build_key
 *
 * Given a pathname, build a DAV_TYPE_FNAME lock database key.
 */

static apr_datum_t dav_generic_build_key(apr_pool_t *p,
                                         const dav_resource *resource)
{
    apr_datum_t key;
    const char *pathname = resource->uri;

    /* ### does this allocation have a proper lifetime? need to check */
    /* ### can we use a buffer for this? */

    /* size is TYPE + pathname + null */
    key.dsize = strlen(pathname) + 2;
    key.dptr = apr_palloc(p, key.dsize);
    *key.dptr = DAV_TYPE_FNAME;
    memcpy(key.dptr + 1, pathname, key.dsize - 1);
    if (key.dptr[key.dsize - 2] == '/')
        key.dptr[--key.dsize - 1] = '\0';
    return key;
}

/*
 * dav_generic_lock_expired:  return 1 (true) if the given timeout is in the
 *    past or present (the lock has expired), or 0 (false) if in the future
 *    (the lock has not yet expired).
 */

static int dav_generic_lock_expired(time_t expires)
{
    return expires != DAV_TIMEOUT_INFINITE && time(NULL) >= expires;
}

/*
 * dav_generic_save_lock_record:  Saves the lock information specified in the
 *    direct and indirect lock lists about path into the lock database.
 *    If direct and indirect == NULL, the key is removed.
 */

static dav_error * dav_generic_save_lock_record(dav_lockdb *lockdb,
                                                apr_datum_t key,
                                                dav_lock_discovery *direct,
                                                dav_lock_indirect *indirect)
{
    dav_error *err;
    apr_status_t status;
    apr_datum_t val = { 0 };
    char *ptr;
    dav_lock_discovery *dp = direct;
    dav_lock_indirect *ip = indirect;

#if DAV_DEBUG
    if (lockdb->ro) {
        return dav_new_error(lockdb->info->pool,
                             HTTP_INTERNAL_SERVER_ERROR, 0, 0,
                             "INTERNAL DESIGN ERROR: the lockdb was opened "
                             "readonly, but an attempt to save locks was "
                             "performed.");
    }
#endif

    if ((err = dav_generic_really_open_lockdb(lockdb)) != NULL) {
        /* ### add a higher-level error? */
        return err;
    }

    /* If nothing to save, delete key */
    if (dp == NULL && ip == NULL) {
        /* don't fail if the key is not present */
        /* ### but what about other errors? */
        apr_dbm_delete(lockdb->info->db, key);
        return NULL;
    }

    while (dp) {
        val.dsize += dav_size_direct(dp);
        dp = dp->next;
    }
    while (ip) {
        val.dsize += dav_size_indirect(ip);
        ip = ip->next;
    }

    /* ### can this be apr_palloc() ? */
    /* ### hmmm.... investigate the use of a buffer here */
    ptr = val.dptr = apr_pcalloc(lockdb->info->pool, val.dsize);
    dp  = direct;
    ip  = indirect;

    while (dp) {
        /* Direct lock - lock_discovery struct follows */
        *ptr++ = DAV_LOCK_DIRECT;
        memcpy(ptr, dp, sizeof(dp->f));        /* Fixed portion of struct */
        ptr += sizeof(dp->f);
        memcpy(ptr, dp->locktoken, sizeof(*dp->locktoken));
        ptr += sizeof(*dp->locktoken);
        if (dp->owner == NULL) {
            *ptr++ = '\0';
        }
        else {
            memcpy(ptr, dp->owner, strlen(dp->owner) + 1);
            ptr += strlen(dp->owner) + 1;
        }
        if (dp->auth_user == NULL) {
            *ptr++ = '\0';
        }
        else {
            memcpy(ptr, dp->auth_user, strlen(dp->auth_user) + 1);
            ptr += strlen(dp->auth_user) + 1;
        }

        dp = dp->next;
    }

    while (ip) {
        /* Indirect lock prefix */
        *ptr++ = DAV_LOCK_INDIRECT;

        memcpy(ptr, ip->locktoken, sizeof(*ip->locktoken));
        ptr += sizeof(*ip->locktoken);

        memcpy(ptr, &ip->timeout, sizeof(ip->timeout));
        ptr += sizeof(ip->timeout);

        memcpy(ptr, &ip->key.dsize, sizeof(ip->key.dsize));
        ptr += sizeof(ip->key.dsize);

        memcpy(ptr, ip->key.dptr, ip->key.dsize);
        ptr += ip->key.dsize;

        ip = ip->next;
    }

    if ((status = apr_dbm_store(lockdb->info->db, key, val)) != APR_SUCCESS) {
        /* ### more details? add an error_id? */
        err = dav_generic_dbm_new_error(lockdb->info->db, lockdb->info->pool,
                                        status);
        return dav_push_error(lockdb->info->pool,
                              HTTP_INTERNAL_SERVER_ERROR,
                              DAV_ERR_LOCK_SAVE_LOCK,
                              "Could not save lock information.",
                              err);
    }

    return NULL;
}

/*
 * dav_load_lock_record:  Reads lock information about key from lock db;
 *    creates linked lists of the direct and indirect locks.
 *
 *    If add_method = DAV_APPEND_LIST, the result will be appended to the
 *    head of the direct and indirect lists supplied.
 *
 *    Passive lock removal:  If lock has timed out, it will not be returned.
 *    ### How much "logging" does RFC 2518 require?
 */

static dav_error * dav_generic_load_lock_record(dav_lockdb *lockdb,
                                                apr_datum_t key,
                                                int add_method,
                                                dav_lock_discovery **direct,
                                                dav_lock_indirect **indirect)
{
    apr_pool_t *p = lockdb->info->pool;
    dav_error *err;
    apr_status_t status;
    apr_size_t offset = 0;
    int need_save = DAV_FALSE;
    apr_datum_t val = { 0 };
    dav_lock_discovery *dp;
    dav_lock_indirect *ip;

    if (add_method != DAV_APPEND_LIST) {
        *direct = NULL;
        *indirect = NULL;
    }

    if ((err = dav_generic_really_open_lockdb(lockdb)) != NULL) {
        /* ### add a higher-level error? */
        return err;
    }

    /*
     * If we opened readonly and the db wasn't there, then there are no
     * locks for this resource. Just exit.
     */

    if (lockdb->info->db == NULL) {
        return NULL;
    }

    if ((status = apr_dbm_fetch(lockdb->info->db, key, &val)) != APR_SUCCESS) {
        return dav_generic_dbm_new_error(lockdb->info->db, p, status);
    }

    if (!val.dsize) {
        return NULL;
    }

    while (offset < val.dsize) {
        switch (*(val.dptr + offset++)) {
        case DAV_LOCK_DIRECT:
            /* Create and fill a dav_lock_discovery structure */

            dp = apr_pcalloc(p, sizeof(*dp));

            /* Copy the dav_lock_discovery_fixed portion */
            memcpy(dp, val.dptr + offset, sizeof(dp->f));
            offset += sizeof(dp->f);

            /* Copy the lock token. */
            dp->locktoken = apr_pmemdup(p, val.dptr + offset, sizeof(*dp->locktoken));
            offset += sizeof(*dp->locktoken);

            /* Do we have an owner field? */
            if (*(val.dptr + offset) == '\0') {
                ++offset;
            }
            else {
                apr_size_t len = strlen(val.dptr + offset);
                dp->owner = apr_pstrmemdup(p, val.dptr + offset, len);
                offset += len + 1;
            }

            if (*(val.dptr + offset) == '\0') {
                ++offset;
            }
            else {
                apr_size_t len = strlen(val.dptr + offset);
                dp->auth_user = apr_pstrmemdup(p, val.dptr + offset, len);
                offset += len + 1;
            }

            if (!dav_generic_lock_expired(dp->f.timeout)) {
                dp->next = *direct;
                *direct = dp;
            }
            else {
                need_save = DAV_TRUE;
            }
            break;

        case DAV_LOCK_INDIRECT:
            /* Create and fill a dav_lock_indirect structure */

            ip = apr_pcalloc(p, sizeof(*ip));
            ip->locktoken = apr_pmemdup(p, val.dptr + offset, sizeof(*ip->locktoken));
            offset += sizeof(*ip->locktoken);
            memcpy(&ip->timeout, val.dptr + offset, sizeof(ip->timeout));
            offset += sizeof(ip->timeout);
            /* length of datum */
            ip->key.dsize = *((int *) (val.dptr + offset));
            offset += sizeof(ip->key.dsize);
            ip->key.dptr = apr_pmemdup(p, val.dptr + offset, ip->key.dsize);
            offset += ip->key.dsize;

            if (!dav_generic_lock_expired(ip->timeout)) {
                ip->next = *indirect;
                *indirect = ip;
            }
            else {
                need_save = DAV_TRUE;
            }

            break;

        default:
            apr_dbm_freedatum(lockdb->info->db, val);

            /* ### should use a computed_desc and insert corrupt token data */
            --offset;
            return dav_new_error(p,
                                 HTTP_INTERNAL_SERVER_ERROR,
                                 DAV_ERR_LOCK_CORRUPT_DB, 0,
                                 apr_psprintf(p,
                                             "The lock database was found to "
                                             "be corrupt. offset %"
                                             APR_SIZE_T_FMT ", c=%02x",
                                             offset, val.dptr[offset]));
        }
    }

    apr_dbm_freedatum(lockdb->info->db, val);

    /* Clean up this record if we found expired locks */
    /*
     * ### shouldn't do this if we've been opened READONLY. elide the
     * ### timed-out locks from the response, but don't save that info back
     */

    if (need_save == DAV_TRUE) {
        return dav_generic_save_lock_record(lockdb, key, *direct, *indirect);
    }

    return NULL;
}

/* resolve <indirect>, returning <*direct> */
static dav_error * dav_generic_resolve(dav_lockdb *lockdb,
                                       dav_lock_indirect *indirect,
                                       dav_lock_discovery **direct,
                                       dav_lock_discovery **ref_dp,
                                       dav_lock_indirect **ref_ip)
{
    dav_error *err;
    dav_lock_discovery *dir;
    dav_lock_indirect *ind;

    if ((err = dav_generic_load_lock_record(lockdb, indirect->key,
                                       DAV_CREATE_LIST,
                                       &dir, &ind)) != NULL) {
        /* ### insert a higher-level description? */
        return err;
    }
    if (ref_dp != NULL) {
        *ref_dp = dir;
        *ref_ip = ind;
    }

    for (; dir != NULL; dir = dir->next) {
        if (!dav_compare_locktoken(indirect->locktoken, dir->locktoken)) {
            *direct = dir;
            return NULL;
        }
    }

    /* No match found (but we should have found one!) */

    /* ### use a different description and/or error ID? */
    return dav_new_error(lockdb->info->pool,
                         HTTP_INTERNAL_SERVER_ERROR,
                         DAV_ERR_LOCK_CORRUPT_DB, 0,
                         "The lock database was found to be corrupt. "
                         "An indirect lock's direct lock could not "
                         "be found.");
}

/* ---------------------------------------------------------------
 *
 * Property-related lock functions
 *
 */


/*
 * dav_generic_get_supportedlock:  Returns a static string for all
 *    supportedlock properties. I think we save more returning a static string
 *    than constructing it every time, though it might look cleaner.
 */

static const char *dav_generic_get_supportedlock(const dav_resource *resource)
{
    static const char supported[] = DEBUG_CR
        "" DEBUG_CR
        "" DEBUG_CR
        "" DEBUG_CR
        "" DEBUG_CR
        "" DEBUG_CR
        "" DEBUG_CR
        "" DEBUG_CR
        "" DEBUG_CR;

    return supported;
}

/* ---------------------------------------------------------------
 *
 * General lock functions
 *
 */


static dav_error * dav_generic_remove_locknull_state(dav_lockdb *lockdb,
                                                 const dav_resource *resource)
{
    /* We don't need to do anything. */
    return NULL;
}

static dav_error * dav_generic_create_lock(dav_lockdb *lockdb,
                                      const dav_resource *resource,
                                      dav_lock **lock)
{
    apr_datum_t key;

    key = dav_generic_build_key(lockdb->info->pool, resource);

    *lock = dav_generic_alloc_lock(lockdb, key, NULL);

    (*lock)->is_locknull = !resource->exists;

    return NULL;
}

static dav_error * dav_generic_get_locks(dav_lockdb *lockdb,
                                         const dav_resource *resource,
                                         int calltype,
                                         dav_lock **locks)
{
    apr_pool_t *p = lockdb->info->pool;
    apr_datum_t key;
    dav_error *err;
    dav_lock *lock = NULL;
    dav_lock *newlock;
    dav_lock_discovery *dp;
    dav_lock_indirect *ip;

#if DAV_DEBUG
    if (calltype == DAV_GETLOCKS_COMPLETE) {
        return dav_new_error(lockdb->info->pool,
                             HTTP_INTERNAL_SERVER_ERROR, 0, 0,
                             "INTERNAL DESIGN ERROR: DAV_GETLOCKS_COMPLETE "
                             "is not yet supported");
    }
#endif

    key = dav_generic_build_key(p, resource);
    if ((err = dav_generic_load_lock_record(lockdb, key, DAV_CREATE_LIST,
                                            &dp, &ip)) != NULL) {
        /* ### push a higher-level desc? */
        return err;
    }

    /* copy all direct locks to the result list */
    for (; dp != NULL; dp = dp->next) {
        newlock = dav_generic_alloc_lock(lockdb, key, dp->locktoken);
        newlock->is_locknull = !resource->exists;
        newlock->scope = dp->f.scope;
        newlock->type = dp->f.type;
        newlock->depth = dp->f.depth;
        newlock->timeout = dp->f.timeout;
        newlock->owner = dp->owner;
        newlock->auth_user = dp->auth_user;

        /* hook into the result list */
        newlock->next = lock;
        lock = newlock;
    }

    /* copy all the indirect locks to the result list. resolve as needed. */
    for (; ip != NULL; ip = ip->next) {
        newlock = dav_generic_alloc_lock(lockdb, ip->key, ip->locktoken);
        newlock->is_locknull = !resource->exists;

        if (calltype == DAV_GETLOCKS_RESOLVED) {
            err = dav_generic_resolve(lockdb, ip, &dp, NULL, NULL);
            if (err != NULL) {
                /* ### push a higher-level desc? */
                return err;
            }

            newlock->scope = dp->f.scope;
            newlock->type = dp->f.type;
            newlock->depth = dp->f.depth;
            newlock->timeout = dp->f.timeout;
            newlock->owner = dp->owner;
            newlock->auth_user = dp->auth_user;
        }
        else {
            /* DAV_GETLOCKS_PARTIAL */
            newlock->rectype = DAV_LOCKREC_INDIRECT_PARTIAL;
        }

        /* hook into the result list */
        newlock->next = lock;
        lock = newlock;
    }

    *locks = lock;
    return NULL;
}

static dav_error * dav_generic_find_lock(dav_lockdb *lockdb,
                                         const dav_resource *resource,
                                         const dav_locktoken *locktoken,
                                         int partial_ok,
                                         dav_lock **lock)
{
    dav_error *err;
    apr_datum_t key;
    dav_lock_discovery *dp;
    dav_lock_indirect *ip;

    *lock = NULL;

    key = dav_generic_build_key(lockdb->info->pool, resource);
    if ((err = dav_generic_load_lock_record(lockdb, key, DAV_CREATE_LIST,
                                       &dp, &ip)) != NULL) {
        /* ### push a higher-level desc? */
        return err;
    }

    for (; dp != NULL; dp = dp->next) {
        if (!dav_compare_locktoken(locktoken, dp->locktoken)) {
            *lock = dav_generic_alloc_lock(lockdb, key, locktoken);
            (*lock)->is_locknull = !resource->exists;
            (*lock)->scope = dp->f.scope;
            (*lock)->type = dp->f.type;
            (*lock)->depth = dp->f.depth;
            (*lock)->timeout = dp->f.timeout;
            (*lock)->owner = dp->owner;
            (*lock)->auth_user = dp->auth_user;
            return NULL;
        }
    }

    for (; ip != NULL; ip = ip->next) {
        if (!dav_compare_locktoken(locktoken, ip->locktoken)) {
            *lock = dav_generic_alloc_lock(lockdb, ip->key, locktoken);
            (*lock)->is_locknull = !resource->exists;

            /* ### nobody uses the resolving right now! */
            if (partial_ok) {
                (*lock)->rectype = DAV_LOCKREC_INDIRECT_PARTIAL;
            }
            else {
                (*lock)->rectype = DAV_LOCKREC_INDIRECT;
                if ((err = dav_generic_resolve(lockdb, ip, &dp,
                                          NULL, NULL)) != NULL) {
                    /* ### push a higher-level desc? */
                    return err;
                }
                (*lock)->scope = dp->f.scope;
                (*lock)->type = dp->f.type;
                (*lock)->depth = dp->f.depth;
                (*lock)->timeout = dp->f.timeout;
                (*lock)->owner = dp->owner;
                (*lock)->auth_user = dp->auth_user;
            }
            return NULL;
        }
    }

    return NULL;
}

static dav_error * dav_generic_has_locks(dav_lockdb *lockdb,
                                         const dav_resource *resource,
                                         int *locks_present)
{
    dav_error *err;
    apr_datum_t key;

    *locks_present = 0;

    if ((err = dav_generic_really_open_lockdb(lockdb)) != NULL) {
        /* ### insert a higher-level error description */
        return err;
    }

    /*
     * If we opened readonly and the db wasn't there, then there are no
     * locks for this resource. Just exit.
     */

    if (lockdb->info->db == NULL)
        return NULL;

    key = dav_generic_build_key(lockdb->info->pool, resource);

    *locks_present = apr_dbm_exists(lockdb->info->db, key);

    return NULL;
}

static dav_error * dav_generic_append_locks(dav_lockdb *lockdb,
                                            const dav_resource *resource,
                                            int make_indirect,
                                            const dav_lock *lock)
{
    apr_pool_t *p = lockdb->info->pool;
    dav_error *err;
    dav_lock_indirect *ip;
    dav_lock_discovery *dp;
    apr_datum_t key;

    key = dav_generic_build_key(lockdb->info->pool, resource);

    err = dav_generic_load_lock_record(lockdb, key, 0, &dp, &ip);
    if (err != NULL) {
        /* ### maybe add in a higher-level description */
        return err;
    }

    /*
     * ### when we store the lock more directly, we need to update
     * ### lock->rectype and lock->is_locknull
     */


    if (make_indirect) {
        for (; lock != NULL; lock = lock->next) {

            /* ### this works for any <lock> rectype */
            dav_lock_indirect *newi = apr_pcalloc(p, sizeof(*newi));

            /* ### shut off the const warning for now */
            newi->locktoken = (dav_locktoken *)lock->locktoken;
            newi->timeout   = lock->timeout;
            newi->key       = lock->info->key;
            newi->next      = ip;
            ip              = newi;
        }
    }
    else {
        for (; lock != NULL; lock = lock->next) {
            /* create and link in the right kind of lock */

            if (lock->rectype == DAV_LOCKREC_DIRECT) {
                dav_lock_discovery *newd = apr_pcalloc(p, sizeof(*newd));

                newd->f.scope = lock->scope;
                newd->f.type = lock->type;
                newd->f.depth = lock->depth;
                newd->f.timeout = lock->timeout;
                /* ### shut off the const warning for now */
                newd->locktoken = (dav_locktoken *)lock->locktoken;
                newd->owner = lock->owner;
                newd->auth_user = lock->auth_user;
                newd->next = dp;
                dp = newd;
            }
            else {
                /* DAV_LOCKREC_INDIRECT(_PARTIAL) */

                dav_lock_indirect *newi = apr_pcalloc(p, sizeof(*newi));

                /* ### shut off the const warning for now */
                newi->locktoken = (dav_locktoken *)lock->locktoken;
                newi->key       = lock->info->key;
                newi->next      = ip;
                ip              = newi;
            }
        }
    }

    if ((err = dav_generic_save_lock_record(lockdb, key, dp, ip)) != NULL) {
        /* ### maybe add a higher-level description */
        return err;
    }

    return NULL;
}

static dav_error * dav_generic_remove_lock(dav_lockdb *lockdb,
                                           const dav_resource *resource,
                                           const dav_locktoken *locktoken)
{
    dav_error *err;
    dav_lock_discovery *dh = NULL;
    dav_lock_indirect *ih = NULL;
    apr_datum_t key;

    key = dav_generic_build_key(lockdb->info->pool, resource);

    if (locktoken != NULL) {
        dav_lock_discovery *dp;
        dav_lock_discovery *dprev = NULL;
        dav_lock_indirect *ip;
        dav_lock_indirect *iprev = NULL;

        if ((err = dav_generic_load_lock_record(lockdb, key, DAV_CREATE_LIST,
                                           &dh, &ih)) != NULL) {
            /* ### maybe add a higher-level description */
            return err;
        }

        for (dp = dh; dp != NULL; dp = dp->next) {
            if (dav_compare_locktoken(locktoken, dp->locktoken) == 0) {
                if (dprev)
                    dprev->next = dp->next;
                else
                    dh = dh->next;
            }
            dprev = dp;
        }

        for (ip = ih; ip != NULL; ip = ip->next) {
            if (dav_compare_locktoken(locktoken, ip->locktoken) == 0) {
                if (iprev)
                    iprev->next = ip->next;
                else
                    ih = ih->next;
            }
            iprev = ip;
        }

    }

    /* save the modified locks, or remove all locks (dh=ih=NULL). */
    if ((err = dav_generic_save_lock_record(lockdb, key, dh, ih)) != NULL) {
        /* ### maybe add a higher-level description */
        return err;
    }

    return NULL;
}

static int dav_generic_do_refresh(dav_lock_discovery *dp,
                                  const dav_locktoken_list *ltl,
                                  time_t new_time)
{
    int dirty = 0;

    for (; ltl != NULL; ltl = ltl->next) {
        if (dav_compare_locktoken(dp->locktoken, ltl->locktoken) == 0)
        {
            dp->f.timeout = new_time;
            dirty = 1;
            break;
        }
    }

    return dirty;
}

static dav_error * dav_generic_refresh_locks(dav_lockdb *lockdb,
                                             const dav_resource *resource,
                                             const dav_locktoken_list *ltl,
                                             time_t new_time,
                                             dav_lock **locks)
{
    dav_error *err;
    apr_datum_t key;
    dav_lock_discovery *dp;
    dav_lock_discovery *dp_scan;
    dav_lock_indirect *ip;
    int dirty = 0;
    dav_lock *newlock;

    *locks = NULL;

    key = dav_generic_build_key(lockdb->info->pool, resource);
    if ((err = dav_generic_load_lock_record(lockdb, key, DAV_CREATE_LIST,
                                            &dp, &ip)) != NULL) {
        /* ### maybe add in a higher-level description */
        return err;
    }

    /* ### we should be refreshing direct AND (resolved) indirect locks! */

    /* refresh all of the direct locks on this resource */
    for (dp_scan = dp; dp_scan != NULL; dp_scan = dp_scan->next) {
        if (dav_generic_do_refresh(dp_scan, ltl, new_time)) {
            /* the lock was refreshed. return the lock. */
            newlock = dav_generic_alloc_lock(lockdb, key, dp_scan->locktoken);
            newlock->is_locknull = !resource->exists;
            newlock->scope = dp_scan->f.scope;
            newlock->type = dp_scan->f.type;
            newlock->depth = dp_scan->f.depth;
            newlock->timeout = dp_scan->f.timeout;
            newlock->owner = dp_scan->owner;
            newlock->auth_user = dp_scan->auth_user;

            newlock->next = *locks;
            *locks = newlock;

            dirty = 1;
        }
    }

    /* if we refreshed any locks, then save them back. */
    if (dirty
        && (err = dav_generic_save_lock_record(lockdb, key, dp, ip)) != NULL) {
        /* ### maybe add in a higher-level description */
        return err;
    }

    /* for each indirect lock, find its direct lock and refresh it. */
    for (; ip != NULL; ip = ip->next) {
        dav_lock_discovery *ref_dp;
        dav_lock_indirect *ref_ip;

        if ((err = dav_generic_resolve(lockdb, ip, &dp_scan,
                                       &ref_dp, &ref_ip)) != NULL) {
            /* ### push a higher-level desc? */
            return err;
        }
        if (dav_generic_do_refresh(dp_scan, ltl, new_time)) {
            /* the lock was refreshed. return the lock. */
            newlock = dav_generic_alloc_lock(lockdb, ip->key, dp->locktoken);
            newlock->is_locknull = !resource->exists;
            newlock->scope = dp->f.scope;
            newlock->type = dp->f.type;
            newlock->depth = dp->f.depth;
            newlock->timeout = dp->f.timeout;
            newlock->owner = dp->owner;
            newlock->auth_user = dp_scan->auth_user;

            newlock->next = *locks;
            *locks = newlock;

            /* save the (resolved) direct lock back */
            if ((err = dav_generic_save_lock_record(lockdb, ip->key, ref_dp,
                                                    ref_ip)) != NULL) {
                /* ### push a higher-level desc? */
                return err;
            }
        }
    }

    return NULL;
}


const dav_hooks_locks dav_hooks_locks_generic =
{
    dav_generic_get_supportedlock,
    dav_generic_parse_locktoken,
    dav_generic_format_locktoken,
    dav_generic_compare_locktoken,
    dav_generic_open_lockdb,
    dav_generic_close_lockdb,
    dav_generic_remove_locknull_state,
    dav_generic_create_lock,
    dav_generic_get_locks,
    dav_generic_find_lock,
    dav_generic_has_locks,
    dav_generic_append_locks,
    dav_generic_remove_lock,
    dav_generic_refresh_locks,
    NULL, /* lookup_resource */

    NULL /* ctx */
};

95%


¤ Dauer der Verarbeitung: 0.32 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.