lock.c revision 7a4999217dfa98039f66724f390511e3a4e4ae8c
* 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact apache@apache.org. * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * ==================================================================== * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see ** DAV filesystem lock implementation /* --------------------------------------------------------------- ** Lock database primitives ** Lockdiscovery information is stored in the single lock database specified ** by the DAVLockDB directive. Information about this db is stored in the ** global server configuration. ** The database is keyed by a key_type unsigned char (DAV_TYPE_INODE or ** DAV_TYPE_FNAME) followed by inode and device number if possible, ** otherwise full path (in the case of Win32 or lock-null resources). ** The value consists of a list of elements. ** DIRECT LOCK: [char (DAV_LOCK_DIRECT), ** char (dav_lock_scope), ** INDIRECT LOCK: [char (DAV_LOCK_INDIRECT), ** The key is to the collection lock that resulted in this indirect lock /* Stored lock_discovery prefix */ /* ack. forward declare. */ ** Use the opaquelock scheme for locktokens /* ################################################################# ** ### 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. const char *
owner;
/* owner field from activelock */ const char *
auth_user;
/* authenticated user who created the lock */ /* 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 /* ################################################################# */ ** Stored direct lock info - full lock_discovery length: ** prefix + Fixed length + lock token + 2 strings + 2 nulls (one for each string) /* Stored indirect lock info - lock token and apr_datum_t */ ** 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. const char *
lockdb_path;
/* where is the lock database? */ int opened;
/* we opened the database */ dav_db *
db;
/* if non-NULL, the lock database */ ** The private part of the lock structure. ** This must be forward-declared so the open_lockdb function can use it. /* internal function for creating locks */ ** dav_fs_parse_locktoken ** Parse an opaquelocktoken URI into a locktoken. "The lock token uses an unknown State-token " "format and could not be parsed.");
"The opaquelocktoken has an incorrect format " "and could not be parsed.");
** dav_fs_format_locktoken ** Generate the URI for a locktoken ** dav_fs_compare_locktoken ** Determine whether two locktokens are the same ** dav_fs_really_open_lockdb: ** If the database hasn't been opened yet, then open the thing. "Could not open the lock database.",
/* all right. it is opened now. */ ** "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. "A lock database was not specified with the " "DAVLockDB directive. One must be specified " "to use the locking functionality.");
/* done initializing. return it. */ /* ### add a higher-level comment? */ ** dav_fs_build_fname_key ** Given a pathname, build a DAV_TYPE_FNAME lock database key. /* ### does this allocation have a proper lifetime? need to check */ /* ### can we use a buffer for this? */ /* size is TYPE + pathname + null */ ** dav_fs_build_key: Given a resource, return a apr_datum_t key ** to look up lock information for this file. ** (Win32 or file is lock-null): ** apr_datum_t->dvalue = full path ** (non-Win32 and file exists ): ** apr_datum_t->dvalue = inode, dev_major, dev_minor /* ### can we use a buffer for this? */ ** dav_fs_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). ** dav_fs_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. "INTERNAL DESIGN ERROR: the lockdb was opened " "readonly, but an attempt to save locks was " /* ### add a higher-level error? */ /* If nothing to save, delete key */ /* don't fail if the key is not present */ /* ### but what about other errors? */ /* ### can this be apr_palloc() ? */ /* ### hmmm.... investigate the use of a buffer here */ /* ### more details? add an error_id? */ "Could not save lock information.",
** 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? /* ### add a higher-level error? */ ** If we opened readonly and the db wasn't there, then there are no ** locks for this resource. Just exit. /* Create and fill a dav_lock_discovery structure */ /* Remove timed-out locknull fm .locknull list */ /* if we don't see the file, then it's a locknull */ /* ### push a higher-level description? */ /* Create and fill a dav_lock_indirect structure */ /* A locknull resource will never be locked indirectly */ /* ### should use a computed_desc and insert corrupt token data */ "The lock database was found to " /* 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 /* resolve <indirect>, returning <*direct> */ /* ### insert a higher-level description? */ /* No match found (but we should have found one!) */ /* ### use a different description and/or error ID? */ "The lock database was found to be corrupt. " "An indirect lock's direct lock could not " /* --------------------------------------------------------------- ** Property-related lock functions ** dav_fs_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. "<D:lockscope><D:exclusive/></D:lockscope>" DEBUG_CR "<D:locktype><D:write/></D:locktype>" DEBUG_CR "<D:lockscope><D:shared/></D:lockscope>" DEBUG_CR "<D:locktype><D:write/></D:locktype>" DEBUG_CR /* --------------------------------------------------------------- ** General lock functions /* --------------------------------------------------------------- ** Functions dealing with lock-null resources ** dav_fs_load_locknull_list: Returns a dav_buffer dump of the locknull file ** for the given directory. /* reset this in case we leave w/o reading into the buffer */ "Opened but could not stat file %s",
"Opened but rejected huge file %s",
"Failure reading locknull file " /* just in case the caller disregards the returned error */ ** dav_fs_save_locknull_list: Saves contents of pbuf into the ** locknull file for dirpath. /* delete the file if cur_len == 0 */ "Error opening %s for writing",
** dav_fs_remove_locknull_member: Removes filename from the locknull list /* ### add a higher level description? */ /* ### add a higher level description? */ /* ### fold into append_lock? */ /* ### take an optional buf parameter? */ "Could not load .locknull file.",
err);
"Could not save .locknull file.",
err);
** dav_fs_remove_locknull_state: Given a request, check to see if r->filename ** is/was a lock-null resource. If so, return it to an existant state. ** ### this function is broken... it doesn't check! ** In this implementation, this involves two things: ** (a) remove it from the list in the appropriate .DAV/locknull file ** (b) on *nix, convert the key from a filename to an inode. /* ### add a higher-level description? */ ** Fetch the lock(s) that made the resource lock-null. Remove ** them under the filename key. Obtain the new inode key, and ** save the same lock information under it. /* ### insert a higher-level error description */ /* ### insert a higher-level error description */ /* ### insert a higher-level error description */ "INTERNAL DESIGN ERROR: DAV_GETLOCKS_COMPLETE " /* ### push a higher-level desc? */ /* copy all direct locks to the result list */ /* hook into the result list */ /* copy all the indirect locks to the result list. resolve as needed. */ /* ### push a higher-level desc? */ /* DAV_GETLOCKS_PARTIAL */ /* hook into the result list */ /* ### push a higher-level desc? */ /* ### nobody uses the resolving right now! */ /* ### push a higher-level desc? */ /* ### insert a higher-level error description */ ** If we opened readonly and the db wasn't there, then there are no ** locks for this resource. Just exit. /* ### maybe add in a higher-level description */ ** ### when we store the lock more directly, we need to update ** ### lock->rectype and lock->is_locknull /* ### this works for any <lock> rectype */ /* ### shut off the const warning for now */ /* create and link in the right kind of lock */ /* ### shut off the const warning for now */ /* DAV_LOCKREC_INDIRECT(_PARTIAL) */ /* ### shut off the const warning for now */ /* ### maybe add a higher-level description */ /* we have a special list for recording locknull resources */ /* ### ack! this can add two copies to the locknull list */ /* ### maybe add a higher-level description */ /* ### maybe add a higher-level description */ /* save the modified locks, or remove all locks (dh=ih=NULL). */ /* ### maybe add a higher-level description */ ** If this resource is a locknull resource AND no more locks exist, ** then remove the locknull member. ** Note: remove_locknull_state() attempts to convert a locknull member ** to a real member. In this case, all locks are gone, so the ** locknull resource returns to the null state (ie. doesn't exist), ** so there is no need to update the lockdb (and it won't find ** any because a precondition is that none exist). /* ### maybe add a higher-level description */ /* ### maybe add in a higher-level description */ /* ### we should be refreshing direct AND (resolved) indirect locks! */ /* refresh all of the direct locks on this resource */ /* the lock was refreshed. return the lock. */ /* if we refreshed any locks, then save them back. */ /* ### maybe add in a higher-level description */ /* for each indirect lock, find its direct lock and refresh it. */ /* ### push a higher-level desc? */ /* the lock was refreshed. return the lock. */ /* save the (resolved) direct lock back */ /* ### push a higher-level desc? */