⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 util_lock.c

📁 Apache 2.0.63 is the current stable version of the 2.0 series, and is recommended over any previous
💻 C
📖 第 1 页 / 共 2 页
字号:
        /* ### should we stop or return a multistatus? looks like STOP */
        /* ### add a higher-level description? */
        return err;
    }

    return NULL;
}

/*
** dav_get_direct_resource:
**
** Find a lock on the specified resource, then return the resource the
** lock was applied to (in other words, given a (possibly) indirect lock,
** return the direct lock's corresponding resource).
**
** If the lock is an indirect lock, this usually means traversing up the
** namespace [repository] hierarchy. Note that some lock providers may be
** able to return this information with a traversal.
*/
static dav_error * dav_get_direct_resource(apr_pool_t *p,
                                           dav_lockdb *lockdb,
                                           const dav_locktoken *locktoken,
                                           const dav_resource *resource,
                                           const dav_resource **direct_resource)
{
    if (lockdb->hooks->lookup_resource != NULL) {
        return (*lockdb->hooks->lookup_resource)(lockdb, locktoken,
                                                 resource, direct_resource);
    }

    *direct_resource = NULL;

    /* Find the top of this lock-
     * If r->filename's direct   locks include locktoken, use r->filename.
     * If r->filename's indirect locks include locktoken, retry r->filename/..
     * Else fail.
     */
    while (resource != NULL) {
        dav_error *err;
        dav_lock *lock;
        dav_resource *parent;

        /*
        ** Find the lock specified by <locktoken> on <resource>. If it is
        ** an indirect lock, then partial results are okay. We're just
        ** trying to find the thing and know whether it is a direct or
        ** an indirect lock.
        */
        if ((err = (*lockdb->hooks->find_lock)(lockdb, resource, locktoken,
                                               1, &lock)) != NULL) {
            /* ### add a higher-level desc? */
            return err;
        }

        /* not found! that's an error. */
        if (lock == NULL) {
            return dav_new_error(p, HTTP_BAD_REQUEST, 0,
                                 "The specified locktoken does not correspond "
                                 "to an existing lock on this resource.");
        }

        if (lock->rectype == DAV_LOCKREC_DIRECT) {
            /* we found the direct lock. return this resource. */

            *direct_resource = resource;
            return NULL;
        }

        /* the lock was indirect. move up a level in the URL namespace */
        if ((err = (*resource->hooks->get_parent_resource)(resource,
                                                           &parent)) != NULL) {
            /* ### add a higher-level desc? */
            return err;
        }
        resource = parent;
    }

    return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 0,
                         "The lock database is corrupt. A direct lock could "
                         "not be found for the corresponding indirect lock "
                         "on this resource.");
}

/*
** dav_unlock:  Removes all direct and indirect locks for r->filename,
**    with given locktoken.  If locktoken == null_locktoken, all locks
**    are removed.  If r->filename represents an indirect lock,
**    we must unlock the appropriate direct lock.
**    Returns OK or appropriate HTTP_* response and logs any errors.
**
** ### We've already crawled the tree to ensure everything was locked
**     by us; there should be no need to incorporate a rollback.
*/
DAV_DECLARE(int) dav_unlock(request_rec *r, const dav_resource *resource,
                            const dav_locktoken *locktoken)
{
    int result;
    dav_lockdb *lockdb;
    const dav_resource *lock_resource = resource;
    const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);
    const dav_hooks_repository *repos_hooks = resource->hooks;
    dav_walker_ctx ctx = { { 0 } };
    dav_response *multi_status;
    dav_error *err;

    /* If no locks provider, then there is nothing to unlock. */
    if (hooks == NULL) {
        return OK;
    }

    /* 2518 requires the entire lock to be removed if resource/locktoken
     * point to an indirect lock.  We need resource of the _direct_
     * lock in order to walk down the tree and remove the locks.  So,
     * If locktoken != null_locktoken, 
     *    Walk up the resource hierarchy until we see a direct lock.
     *    Or, we could get the direct lock's db/key, pick out the URL
     *    and do a subrequest.  I think walking up is faster and will work
     *    all the time.
     * Else
     *    Just start removing all locks at and below resource.
     */

    if ((err = (*hooks->open_lockdb)(r, 0, 1, &lockdb)) != NULL) {
        /* ### return err! maybe add a higher-level desc */
        /* ### map result to something nice; log an error */
        return HTTP_INTERNAL_SERVER_ERROR;
    }

    if (locktoken != NULL
        && (err = dav_get_direct_resource(r->pool, lockdb,
                                          locktoken, resource,
                                          &lock_resource)) != NULL) {
        /* ### add a higher-level desc? */
        /* ### should return err! */
        return err->status;
    }

    /* At this point, lock_resource/locktoken refers to a direct lock (key), ie
     * the root of a depth > 0 lock, or locktoken is null.
     */
    ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_LOCKNULL;
    ctx.w.func = dav_unlock_walker;
    ctx.w.walk_ctx = &ctx;
    ctx.w.pool = r->pool;
    ctx.w.root = lock_resource;
    ctx.w.lockdb = lockdb;

    ctx.r = r;
    ctx.locktoken = locktoken;

    err = (*repos_hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status);

    /* ### fix this! */
    /* ### do something with multi_status */
    result = err == NULL ? OK : err->status;

    (*hooks->close_lockdb)(lockdb);

    return result;
}

/* dav_inherit_walker:  Walker callback function to inherit locks */
static dav_error * dav_inherit_walker(dav_walk_resource *wres, int calltype)
{
    dav_walker_ctx *ctx = wres->walk_ctx;

    if (ctx->skip_root
        && (*wres->resource->hooks->is_same_resource)(wres->resource,
                                                      ctx->w.root)) {
        return NULL;
    }

    /* ### maybe add a higher-level desc */
    return (*ctx->w.lockdb->hooks->append_locks)(ctx->w.lockdb,
                                                 wres->resource, 1,
                                                 ctx->lock);
}

/*
** dav_inherit_locks:  When a resource or collection is added to a collection,
**    locks on the collection should be inherited to the resource/collection.
**    (MOVE, MKCOL, etc) Here we propagate any direct or indirect locks from
**    parent of resource to resource and below.
*/
static dav_error * dav_inherit_locks(request_rec *r, dav_lockdb *lockdb,
                                     const dav_resource *resource,
                                     int use_parent)
{
    dav_error *err;
    const dav_resource *which_resource;
    dav_lock *locks;
    dav_lock *scan;
    dav_lock *prev;
    dav_walker_ctx ctx = { { 0 } };
    const dav_hooks_repository *repos_hooks = resource->hooks;
    dav_response *multi_status;

    if (use_parent) {
        dav_resource *parent;
        if ((err = (*repos_hooks->get_parent_resource)(resource,
                                                       &parent)) != NULL) {
            /* ### add a higher-level desc? */
            return err;
        }
        if (parent == NULL) {
            /* ### map result to something nice; log an error */
            return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
                                 "Could not fetch parent resource. Unable to "
                                 "inherit locks from the parent and apply "
                                 "them to this resource.");
        }
        which_resource = parent;
    }
    else {
        which_resource = resource;
    }

    if ((err = (*lockdb->hooks->get_locks)(lockdb, which_resource,
                                           DAV_GETLOCKS_PARTIAL,
                                           &locks)) != NULL) {
        /* ### maybe add a higher-level desc */
        return err;
    }

    if (locks == NULL) {
        /* No locks to propagate, just return */
        return NULL;
    }

    /*
    ** (1) Copy all indirect locks from our parent;
    ** (2) Create indirect locks for the depth infinity, direct locks
    **     in our parent.
    **
    ** The append_locks call in the walker callback will do the indirect
    ** conversion, but we need to remove any direct locks that are NOT
    ** depth "infinity".
    */
    for (scan = locks, prev = NULL;
         scan != NULL;
         prev = scan, scan = scan->next) {

        if (scan->rectype == DAV_LOCKREC_DIRECT
            && scan->depth != DAV_INFINITY) {

            if (prev == NULL)
                locks = scan->next;
            else
                prev->next = scan->next;
        }
    }

    /* <locks> has all our new locks.  Walk down and propagate them. */

    ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_LOCKNULL;
    ctx.w.func = dav_inherit_walker;
    ctx.w.walk_ctx = &ctx;
    ctx.w.pool = r->pool;
    ctx.w.root = resource;
    ctx.w.lockdb = lockdb;

    ctx.r = r;
    ctx.lock = locks;
    ctx.skip_root = !use_parent;

    /* ### do something with multi_status */
    return (*repos_hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status);
}

/* ---------------------------------------------------------------
**
** Functions dealing with lock-null resources
**
*/

/*
** dav_get_resource_state:  Returns the state of the resource
**    r->filename:  DAV_RESOURCE_NULL, DAV_RESOURCE_LOCK_NULL,
**    or DAV_RESOURCE_EXIST.
**
**    Returns DAV_RESOURCE_ERROR if an error occurs.
*/
DAV_DECLARE(int) dav_get_resource_state(request_rec *r,
                                        const dav_resource *resource)
{
    const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r);

    if (resource->exists)
        return DAV_RESOURCE_EXISTS;

    if (hooks != NULL) {
        dav_error *err;
        dav_lockdb *lockdb;
        int locks_present;

        /*
        ** A locknull resource has the form:
        **
        **   known-dir "/" locknull-file
        **
        ** It would be nice to look into <resource> to verify this form,
        ** but it does not have enough information for us. Instead, we
        ** can look at the path_info. If the form does not match, then
        ** there is no way we could have a locknull resource -- it must
        ** be a plain, null resource.
        **
        ** Apache sets r->filename to known-dir/unknown-file and r->path_info
        ** to "" for the "proper" case. If anything is in path_info, then
        ** it can't be a locknull resource.
        **
        ** ### I bet this path_info hack doesn't work for repositories.
        ** ### Need input from repository implementors! What kind of
        ** ### restructure do we need? New provider APIs?
        */
        if (r->path_info != NULL && *r->path_info != '\0') {
            return DAV_RESOURCE_NULL;
        }
        
        if ((err = (*hooks->open_lockdb)(r, 1, 1, &lockdb)) == NULL) {
            /* note that we might see some expired locks... *shrug* */
            err = (*hooks->has_locks)(lockdb, resource, &locks_present);
            (*hooks->close_lockdb)(lockdb);
        }

        if (err != NULL) {
            /* ### don't log an error. return err. add higher-level desc. */

            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                          "Failed to query lock-null status for %s",
                          r->filename);

            return DAV_RESOURCE_ERROR;
        }

        if (locks_present)
            return DAV_RESOURCE_LOCK_NULL;
    }

    return DAV_RESOURCE_NULL;
}

DAV_DECLARE(dav_error *) dav_notify_created(request_rec *r,
                                            dav_lockdb *lockdb,
                                            const dav_resource *resource,
                                            int resource_state,
                                            int depth)
{
    dav_error *err;

    if (resource_state == DAV_RESOURCE_LOCK_NULL) {

        /*
        ** The resource is no longer a locknull resource. This will remove
        ** the special marker.
        **
        ** Note that a locknull resource has already inherited all of the
        ** locks from the parent. We do not need to call dav_inherit_locks.
        **
        ** NOTE: some lock providers record locks for locknull resources using
        **       a different key than for regular resources. this will shift
        **       the lock information between the two key types.
        */
        (void)(*lockdb->hooks->remove_locknull_state)(lockdb, resource);

        /*
        ** There are resources under this one, which are new. We must
        ** propagate the locks down to the new resources.
        */
        if (depth > 0 &&
            (err = dav_inherit_locks(r, lockdb, resource, 0)) != NULL) {
            /* ### add a higher level desc? */
            return err;
        }
    }
    else if (resource_state == DAV_RESOURCE_NULL) {

        /* ### should pass depth to dav_inherit_locks so that it can
        ** ### optimize for the depth==0 case.
        */

        /* this resource should inherit locks from its parent */
        if ((err = dav_inherit_locks(r, lockdb, resource, 1)) != NULL) {

            err = dav_push_error(r->pool, err->status, 0,
                                 "The resource was created successfully, but "
                                 "there was a problem inheriting locks from "
                                 "the parent resource.",
                                 err);
            return err;
        }
    }
    /* else the resource already exists and its locks are correct. */

    return NULL;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -