📄 util_lock.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. *//*** DAV repository-independent lock functions*/#include "apr.h"#include "apr_strings.h"#if APR_HAVE_STDIO_H#include <stdio.h> /* for sprintf() */#endif#include "mod_dav.h"#include "http_log.h"#include "http_config.h"#include "http_protocol.h"#include "http_core.h"/* ---------------------------------------------------------------**** Property-related lock functions***//*** dav_lock_get_activelock: Returns a <lockdiscovery> containing** an activelock element for every item in the lock_discovery tree*/DAV_DECLARE(const char *) dav_lock_get_activelock(request_rec *r, dav_lock *lock, dav_buffer *pbuf){ dav_lock *lock_scan; const dav_hooks_locks *hooks = DAV_GET_HOOKS_LOCKS(r); int count = 0; dav_buffer work_buf = { 0 }; apr_pool_t *p = r->pool; /* If no locks or no lock provider, there are no locks */ if (lock == NULL || hooks == NULL) { /* ** Since resourcediscovery is defined with (activelock)*, ** <D:activelock/> shouldn't be necessary for an empty lock. */ return ""; } /* ** Note: it could be interesting to sum the lengths of the owners ** and locktokens during this loop. However, the buffer ** mechanism provides some rough padding so that we don't ** really need to have an exact size. Further, constructing ** locktoken strings could be relatively expensive. */ for (lock_scan = lock; lock_scan != NULL; lock_scan = lock_scan->next) count++; /* if a buffer was not provided, then use an internal buffer */ if (pbuf == NULL) pbuf = &work_buf; /* reset the length before we start appending stuff */ pbuf->cur_len = 0; /* prep the buffer with a "good" size */ dav_check_bufsize(p, pbuf, count * 300); for (; lock != NULL; lock = lock->next) { char tmp[100];#if DAV_DEBUG if (lock->rectype == DAV_LOCKREC_INDIRECT_PARTIAL) { /* ### crap. design error */ dav_buffer_append(p, pbuf, "DESIGN ERROR: attempted to product an " "activelock element from a partial, indirect " "lock record. Creating an XML parsing error " "to ease detection of this situation: <"); }#endif dav_buffer_append(p, pbuf, "<D:activelock>" DEBUG_CR "<D:locktype>"); switch (lock->type) { case DAV_LOCKTYPE_WRITE: dav_buffer_append(p, pbuf, "<D:write/>"); break; default: /* ### internal error. log something? */ break; } dav_buffer_append(p, pbuf, "</D:locktype>" DEBUG_CR "<D:lockscope>"); switch (lock->scope) { case DAV_LOCKSCOPE_EXCLUSIVE: dav_buffer_append(p, pbuf, "<D:exclusive/>"); break; case DAV_LOCKSCOPE_SHARED: dav_buffer_append(p, pbuf, "<D:shared/>"); break; default: /* ### internal error. log something? */ break; } dav_buffer_append(p, pbuf, "</D:lockscope>" DEBUG_CR); sprintf(tmp, "<D:depth>%s</D:depth>" DEBUG_CR, lock->depth == DAV_INFINITY ? "infinity" : "0"); dav_buffer_append(p, pbuf, tmp); if (lock->owner) { /* ** This contains a complete, self-contained <DAV:owner> element, ** with namespace declarations and xml:lang handling. Just drop ** it in. */ dav_buffer_append(p, pbuf, lock->owner); } dav_buffer_append(p, pbuf, "<D:timeout>"); if (lock->timeout == DAV_TIMEOUT_INFINITE) { dav_buffer_append(p, pbuf, "Infinite"); } else { time_t now = time(NULL); sprintf(tmp, "Second-%lu", (long unsigned int)(lock->timeout - now)); dav_buffer_append(p, pbuf, tmp); } dav_buffer_append(p, pbuf, "</D:timeout>" DEBUG_CR "<D:locktoken>" DEBUG_CR "<D:href>"); dav_buffer_append(p, pbuf, (*hooks->format_locktoken)(p, lock->locktoken)); dav_buffer_append(p, pbuf, "</D:href>" DEBUG_CR "</D:locktoken>" DEBUG_CR "</D:activelock>" DEBUG_CR); } return pbuf->buf;}/*** dav_lock_parse_lockinfo: Validates the given xml_doc to contain a** lockinfo XML element, then populates a dav_lock structure** with its contents.*/DAV_DECLARE(dav_error *) dav_lock_parse_lockinfo(request_rec *r, const dav_resource *resource, dav_lockdb *lockdb, const apr_xml_doc *doc, dav_lock **lock_request){ apr_pool_t *p = r->pool; dav_error *err; apr_xml_elem *child; dav_lock *lock; if (!dav_validate_root(doc, "lockinfo")) { return dav_new_error(p, HTTP_BAD_REQUEST, 0, "The request body contains an unexpected " "XML root element."); } if ((err = (*lockdb->hooks->create_lock)(lockdb, resource, &lock)) != NULL) { return dav_push_error(p, err->status, 0, "Could not parse the lockinfo due to an " "internal problem creating a lock structure.", err); } lock->depth = dav_get_depth(r, DAV_INFINITY); if (lock->depth == -1) { return dav_new_error(p, HTTP_BAD_REQUEST, 0, "An invalid Depth header was specified."); } lock->timeout = dav_get_timeout(r); /* Parse elements in the XML body */ for (child = doc->root->first_child; child; child = child->next) { if (strcmp(child->name, "locktype") == 0 && child->first_child && lock->type == DAV_LOCKTYPE_UNKNOWN) { if (strcmp(child->first_child->name, "write") == 0) { lock->type = DAV_LOCKTYPE_WRITE; continue; } } if (strcmp(child->name, "lockscope") == 0 && child->first_child && lock->scope == DAV_LOCKSCOPE_UNKNOWN) { if (strcmp(child->first_child->name, "exclusive") == 0) lock->scope = DAV_LOCKSCOPE_EXCLUSIVE; else if (strcmp(child->first_child->name, "shared") == 0) lock->scope = DAV_LOCKSCOPE_SHARED; if (lock->scope != DAV_LOCKSCOPE_UNKNOWN) continue; } if (strcmp(child->name, "owner") == 0 && lock->owner == NULL) { const char *text; /* quote all the values in the <DAV:owner> element */ apr_xml_quote_elem(p, child); /* ** Store a full <DAV:owner> element with namespace definitions ** and an xml:lang definition, if applicable. */ apr_xml_to_text(p, child, APR_XML_X2T_FULL_NS_LANG, doc->namespaces, NULL, &text, NULL); lock->owner = text; continue; } return dav_new_error(p, HTTP_PRECONDITION_FAILED, 0, apr_psprintf(p, "The server cannot satisfy the " "LOCK request due to an unknown XML " "element (\"%s\") within the " "DAV:lockinfo element.", child->name)); } *lock_request = lock; return NULL;}/* ---------------------------------------------------------------**** General lock functions***//* dav_lock_walker: Walker callback function to record indirect locks */static dav_error * dav_lock_walker(dav_walk_resource *wres, int calltype){ dav_walker_ctx *ctx = wres->walk_ctx; dav_error *err; /* We don't want to set indirects on the target */ if ((*wres->resource->hooks->is_same_resource)(wres->resource, ctx->w.root)) return NULL; if ((err = (*ctx->w.lockdb->hooks->append_locks)(ctx->w.lockdb, wres->resource, 1, ctx->lock)) != NULL) { if (ap_is_HTTP_SERVER_ERROR(err->status)) { /* ### add a higher-level description? */ return err; } /* add to the multistatus response */ dav_add_response(wres, err->status, NULL); /* ** ### actually, this is probably wrong: we want to fail the whole ** ### LOCK process if something goes bad. maybe the caller should ** ### do a dav_unlock() (e.g. a rollback) if any errors occurred. */ } return NULL;}/*** dav_add_lock: Add a direct lock for resource, and indirect locks for** all children, bounded by depth.** ### assume request only contains one lock*/DAV_DECLARE(dav_error *) dav_add_lock(request_rec *r, const dav_resource *resource, dav_lockdb *lockdb, dav_lock *lock, dav_response **response){ dav_error *err; int depth = lock->depth; *response = NULL; /* Requested lock can be: * Depth: 0 for null resource, existing resource, or existing collection * Depth: Inf for existing collection */ /* ** 2518 9.2 says to ignore depth if target is not a collection (it has ** no internal children); pretend the client gave the correct depth. */ if (!resource->collection) { depth = 0; } /* In all cases, first add direct entry in lockdb */ /* ** Append the new (direct) lock to the resource's existing locks. ** ** Note: this also handles locknull resources */ if ((err = (*lockdb->hooks->append_locks)(lockdb, resource, 0, lock)) != NULL) { /* ### maybe add a higher-level description */ return err; } if (depth > 0) { /* Walk existing collection and set indirect locks */ dav_walker_ctx ctx = { { 0 } }; dav_response *multi_status; ctx.w.walk_type = DAV_WALKTYPE_NORMAL | DAV_WALKTYPE_AUTH; ctx.w.func = dav_lock_walker; ctx.w.walk_ctx = &ctx; ctx.w.pool = r->pool; ctx.w.root = resource; ctx.w.lockdb = lockdb; ctx.r = r; ctx.lock = lock; err = (*resource->hooks->walk)(&ctx.w, DAV_INFINITY, &multi_status); if (err != NULL) { /* implies a 5xx status code occurred. screw the multistatus */ return err; } if (multi_status != NULL) { /* manufacture a 207 error for the multistatus response */ *response = multi_status; return dav_new_error(r->pool, HTTP_MULTI_STATUS, 0, "Error(s) occurred on resources during the " "addition of a depth lock."); } } return NULL;}/*** dav_lock_query: Opens the lock database. Returns a linked list of** dav_lock structures for all direct locks on path.*/DAV_DECLARE(dav_error*) dav_lock_query(dav_lockdb *lockdb, const dav_resource *resource, dav_lock **locks){ /* If no lock database, return empty result */ if (lockdb == NULL) { *locks = NULL; return NULL; } /* ### insert a higher-level description? */ return (*lockdb->hooks->get_locks)(lockdb, resource, DAV_GETLOCKS_RESOLVED, locks);}/* dav_unlock_walker: Walker callback function to remove indirect locks */static dav_error * dav_unlock_walker(dav_walk_resource *wres, int calltype){ dav_walker_ctx *ctx = wres->walk_ctx; dav_error *err; /* Before removing the lock, do any auto-checkin required */ if (wres->resource->working) { /* ### get rid of this typecast */ if ((err = dav_auto_checkin(ctx->r, (dav_resource *) wres->resource, 0 /*undo*/, 1 /*unlock*/, NULL)) != NULL) { return err; } } if ((err = (*ctx->w.lockdb->hooks->remove_lock)(ctx->w.lockdb, wres->resource, ctx->locktoken)) != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -