1251881Speter/* lock.c : functions for manipulating filesystem locks. 2251881Speter * 3251881Speter * ==================================================================== 4251881Speter * Licensed to the Apache Software Foundation (ASF) under one 5251881Speter * or more contributor license agreements. See the NOTICE file 6251881Speter * distributed with this work for additional information 7251881Speter * regarding copyright ownership. The ASF licenses this file 8251881Speter * to you under the Apache License, Version 2.0 (the 9251881Speter * "License"); you may not use this file except in compliance 10251881Speter * with the License. You may obtain a copy of the License at 11251881Speter * 12251881Speter * http://www.apache.org/licenses/LICENSE-2.0 13251881Speter * 14251881Speter * Unless required by applicable law or agreed to in writing, 15251881Speter * software distributed under the License is distributed on an 16251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17251881Speter * KIND, either express or implied. See the License for the 18251881Speter * specific language governing permissions and limitations 19251881Speter * under the License. 20251881Speter * ==================================================================== 21251881Speter */ 22251881Speter 23251881Speter 24251881Speter#include "svn_hash.h" 25251881Speter#include "svn_pools.h" 26251881Speter#include "svn_error.h" 27251881Speter#include "svn_fs.h" 28251881Speter#include "svn_private_config.h" 29251881Speter 30251881Speter#include <apr_uuid.h> 31251881Speter 32251881Speter#include "lock.h" 33251881Speter#include "tree.h" 34251881Speter#include "err.h" 35251881Speter#include "bdb/locks-table.h" 36251881Speter#include "bdb/lock-tokens-table.h" 37251881Speter#include "util/fs_skels.h" 38251881Speter#include "../libsvn_fs/fs-loader.h" 39251881Speter#include "private/svn_fs_util.h" 40251881Speter#include "private/svn_subr_private.h" 41251881Speter#include "private/svn_dep_compat.h" 42251881Speter 43251881Speter 44251881Speter/* Add LOCK and its associated LOCK_TOKEN (associated with PATH) as 45251881Speter part of TRAIL. */ 46251881Speterstatic svn_error_t * 47251881Speteradd_lock_and_token(svn_lock_t *lock, 48251881Speter const char *lock_token, 49251881Speter const char *path, 50251881Speter trail_t *trail) 51251881Speter{ 52251881Speter SVN_ERR(svn_fs_bdb__lock_add(trail->fs, lock_token, lock, 53251881Speter trail, trail->pool)); 54251881Speter return svn_fs_bdb__lock_token_add(trail->fs, path, lock_token, 55251881Speter trail, trail->pool); 56251881Speter} 57251881Speter 58251881Speter 59251881Speter/* Delete LOCK_TOKEN and its corresponding lock (associated with PATH, 60251881Speter whose KIND is supplied), as part of TRAIL. */ 61251881Speterstatic svn_error_t * 62251881Speterdelete_lock_and_token(const char *lock_token, 63251881Speter const char *path, 64251881Speter trail_t *trail) 65251881Speter{ 66251881Speter SVN_ERR(svn_fs_bdb__lock_delete(trail->fs, lock_token, 67251881Speter trail, trail->pool)); 68251881Speter return svn_fs_bdb__lock_token_delete(trail->fs, path, 69251881Speter trail, trail->pool); 70251881Speter} 71251881Speter 72251881Speter 73251881Speterstruct lock_args 74251881Speter{ 75251881Speter svn_lock_t **lock_p; 76251881Speter const char *path; 77251881Speter const char *token; 78251881Speter const char *comment; 79251881Speter svn_boolean_t is_dav_comment; 80251881Speter svn_boolean_t steal_lock; 81251881Speter apr_time_t expiration_date; 82251881Speter svn_revnum_t current_rev; 83251881Speter}; 84251881Speter 85251881Speter 86251881Speterstatic svn_error_t * 87251881Spetertxn_body_lock(void *baton, trail_t *trail) 88251881Speter{ 89251881Speter struct lock_args *args = baton; 90251881Speter svn_node_kind_t kind = svn_node_file; 91251881Speter svn_lock_t *existing_lock; 92251881Speter svn_lock_t *lock; 93251881Speter 94251881Speter SVN_ERR(svn_fs_base__get_path_kind(&kind, args->path, trail, trail->pool)); 95251881Speter 96251881Speter /* Until we implement directory locks someday, we only allow locks 97251881Speter on files or non-existent paths. */ 98251881Speter if (kind == svn_node_dir) 99251881Speter return SVN_FS__ERR_NOT_FILE(trail->fs, args->path); 100251881Speter 101251881Speter /* While our locking implementation easily supports the locking of 102251881Speter nonexistent paths, we deliberately choose not to allow such madness. */ 103251881Speter if (kind == svn_node_none) 104251881Speter { 105251881Speter if (SVN_IS_VALID_REVNUM(args->current_rev)) 106251881Speter return svn_error_createf( 107251881Speter SVN_ERR_FS_OUT_OF_DATE, NULL, 108251881Speter _("Path '%s' doesn't exist in HEAD revision"), 109251881Speter args->path); 110251881Speter else 111251881Speter return svn_error_createf( 112251881Speter SVN_ERR_FS_NOT_FOUND, NULL, 113251881Speter _("Path '%s' doesn't exist in HEAD revision"), 114251881Speter args->path); 115251881Speter } 116251881Speter 117251881Speter /* There better be a username attached to the fs. */ 118251881Speter if (!trail->fs->access_ctx || !trail->fs->access_ctx->username) 119251881Speter return SVN_FS__ERR_NO_USER(trail->fs); 120251881Speter 121251881Speter /* Is the caller attempting to lock an out-of-date working file? */ 122251881Speter if (SVN_IS_VALID_REVNUM(args->current_rev)) 123251881Speter { 124251881Speter svn_revnum_t created_rev; 125251881Speter SVN_ERR(svn_fs_base__get_path_created_rev(&created_rev, args->path, 126251881Speter trail, trail->pool)); 127251881Speter 128251881Speter /* SVN_INVALID_REVNUM means the path doesn't exist. So 129251881Speter apparently somebody is trying to lock something in their 130251881Speter working copy, but somebody else has deleted the thing 131251881Speter from HEAD. That counts as being 'out of date'. */ 132251881Speter if (! SVN_IS_VALID_REVNUM(created_rev)) 133251881Speter return svn_error_createf(SVN_ERR_FS_OUT_OF_DATE, NULL, 134251881Speter "Path '%s' doesn't exist in HEAD revision", 135251881Speter args->path); 136251881Speter 137251881Speter if (args->current_rev < created_rev) 138251881Speter return svn_error_createf(SVN_ERR_FS_OUT_OF_DATE, NULL, 139251881Speter "Lock failed: newer version of '%s' exists", 140251881Speter args->path); 141251881Speter } 142251881Speter 143251881Speter /* If the caller provided a TOKEN, we *really* need to see 144251881Speter if a lock already exists with that token, and if so, verify that 145251881Speter the lock's path matches PATH. Otherwise we run the risk of 146251881Speter breaking the 1-to-1 mapping of lock tokens to locked paths. */ 147251881Speter if (args->token) 148251881Speter { 149251881Speter svn_lock_t *lock_from_token; 150251881Speter svn_error_t *err = svn_fs_bdb__lock_get(&lock_from_token, trail->fs, 151251881Speter args->token, trail, 152251881Speter trail->pool); 153251881Speter if (err && ((err->apr_err == SVN_ERR_FS_LOCK_EXPIRED) 154251881Speter || (err->apr_err == SVN_ERR_FS_BAD_LOCK_TOKEN))) 155251881Speter { 156251881Speter svn_error_clear(err); 157251881Speter } 158251881Speter else 159251881Speter { 160251881Speter SVN_ERR(err); 161251881Speter if (strcmp(lock_from_token->path, args->path) != 0) 162251881Speter return svn_error_create(SVN_ERR_FS_BAD_LOCK_TOKEN, NULL, 163251881Speter "Lock failed: token refers to existing " 164251881Speter "lock with non-matching path."); 165251881Speter } 166251881Speter } 167251881Speter 168251881Speter /* Is the path already locked? 169251881Speter 170251881Speter Note that this next function call will automatically ignore any 171251881Speter errors about {the path not existing as a key, the path's token 172251881Speter not existing as a key, the lock just having been expired}. And 173251881Speter that's totally fine. Any of these three errors are perfectly 174251881Speter acceptable to ignore; it means that the path is now free and 175251881Speter clear for locking, because the bdb funcs just cleared out both 176251881Speter of the tables for us. */ 177251881Speter SVN_ERR(svn_fs_base__get_lock_helper(&existing_lock, args->path, 178251881Speter trail, trail->pool)); 179251881Speter if (existing_lock) 180251881Speter { 181251881Speter if (! args->steal_lock) 182251881Speter { 183251881Speter /* Sorry, the path is already locked. */ 184251881Speter return SVN_FS__ERR_PATH_ALREADY_LOCKED(trail->fs, 185251881Speter existing_lock); 186251881Speter } 187251881Speter else 188251881Speter { 189251881Speter /* ARGS->steal_lock is set, so fs_username is "stealing" the 190251881Speter lock from lock->owner. Destroy the existing lock. */ 191251881Speter SVN_ERR(delete_lock_and_token(existing_lock->token, 192251881Speter existing_lock->path, trail)); 193251881Speter } 194251881Speter } 195251881Speter 196251881Speter /* Create a new lock, and add it to the tables. */ 197251881Speter lock = svn_lock_create(trail->pool); 198251881Speter if (args->token) 199251881Speter lock->token = apr_pstrdup(trail->pool, args->token); 200251881Speter else 201251881Speter SVN_ERR(svn_fs_base__generate_lock_token(&(lock->token), trail->fs, 202251881Speter trail->pool)); 203251881Speter lock->path = apr_pstrdup(trail->pool, args->path); 204251881Speter lock->owner = apr_pstrdup(trail->pool, trail->fs->access_ctx->username); 205251881Speter lock->comment = apr_pstrdup(trail->pool, args->comment); 206251881Speter lock->is_dav_comment = args->is_dav_comment; 207251881Speter lock->creation_date = apr_time_now(); 208251881Speter lock->expiration_date = args->expiration_date; 209251881Speter SVN_ERR(add_lock_and_token(lock, lock->token, args->path, trail)); 210251881Speter *(args->lock_p) = lock; 211251881Speter 212251881Speter return SVN_NO_ERROR; 213251881Speter} 214251881Speter 215251881Speter 216251881Speter 217251881Spetersvn_error_t * 218251881Spetersvn_fs_base__lock(svn_lock_t **lock, 219251881Speter svn_fs_t *fs, 220251881Speter const char *path, 221251881Speter const char *token, 222251881Speter const char *comment, 223251881Speter svn_boolean_t is_dav_comment, 224251881Speter apr_time_t expiration_date, 225251881Speter svn_revnum_t current_rev, 226251881Speter svn_boolean_t steal_lock, 227251881Speter apr_pool_t *pool) 228251881Speter{ 229251881Speter struct lock_args args; 230251881Speter 231251881Speter SVN_ERR(svn_fs__check_fs(fs, TRUE)); 232251881Speter 233251881Speter args.lock_p = lock; 234251881Speter args.path = svn_fs__canonicalize_abspath(path, pool); 235251881Speter args.token = token; 236251881Speter args.comment = comment; 237251881Speter args.is_dav_comment = is_dav_comment; 238251881Speter args.steal_lock = steal_lock; 239251881Speter args.expiration_date = expiration_date; 240251881Speter args.current_rev = current_rev; 241251881Speter 242251881Speter return svn_fs_base__retry_txn(fs, txn_body_lock, &args, FALSE, pool); 243251881Speter} 244251881Speter 245251881Speter 246251881Spetersvn_error_t * 247251881Spetersvn_fs_base__generate_lock_token(const char **token, 248251881Speter svn_fs_t *fs, 249251881Speter apr_pool_t *pool) 250251881Speter{ 251251881Speter /* Notice that 'fs' is currently unused. But perhaps someday, we'll 252251881Speter want to use the fs UUID + some incremented number? For now, we 253251881Speter generate a URI that matches the DAV RFC. We could change this to 254251881Speter some other URI scheme someday, if we wish. */ 255251881Speter *token = apr_pstrcat(pool, "opaquelocktoken:", 256251881Speter svn_uuid_generate(pool), (char *)NULL); 257251881Speter return SVN_NO_ERROR; 258251881Speter} 259251881Speter 260251881Speter 261251881Speterstruct unlock_args 262251881Speter{ 263251881Speter const char *path; 264251881Speter const char *token; 265251881Speter svn_boolean_t break_lock; 266251881Speter}; 267251881Speter 268251881Speter 269251881Speterstatic svn_error_t * 270251881Spetertxn_body_unlock(void *baton, trail_t *trail) 271251881Speter{ 272251881Speter struct unlock_args *args = baton; 273251881Speter const char *lock_token; 274251881Speter svn_lock_t *lock; 275251881Speter 276251881Speter /* This could return SVN_ERR_FS_BAD_LOCK_TOKEN or SVN_ERR_FS_LOCK_EXPIRED. */ 277251881Speter SVN_ERR(svn_fs_bdb__lock_token_get(&lock_token, trail->fs, args->path, 278251881Speter trail, trail->pool)); 279251881Speter 280251881Speter /* If not breaking the lock, we need to do some more checking. */ 281251881Speter if (!args->break_lock) 282251881Speter { 283251881Speter /* Sanity check: The lock token must exist, and must match. */ 284251881Speter if (args->token == NULL) 285251881Speter return svn_fs_base__err_no_lock_token(trail->fs, args->path); 286251881Speter else if (strcmp(lock_token, args->token) != 0) 287251881Speter return SVN_FS__ERR_NO_SUCH_LOCK(trail->fs, args->path); 288251881Speter 289251881Speter SVN_ERR(svn_fs_bdb__lock_get(&lock, trail->fs, lock_token, 290251881Speter trail, trail->pool)); 291251881Speter 292251881Speter /* There better be a username attached to the fs. */ 293251881Speter if (!trail->fs->access_ctx || !trail->fs->access_ctx->username) 294251881Speter return SVN_FS__ERR_NO_USER(trail->fs); 295251881Speter 296251881Speter /* And that username better be the same as the lock's owner. */ 297251881Speter if (strcmp(trail->fs->access_ctx->username, lock->owner) != 0) 298251881Speter return SVN_FS__ERR_LOCK_OWNER_MISMATCH( 299251881Speter trail->fs, 300251881Speter trail->fs->access_ctx->username, 301251881Speter lock->owner); 302251881Speter } 303251881Speter 304251881Speter /* Remove a row from each of the locking tables. */ 305251881Speter return delete_lock_and_token(lock_token, args->path, trail); 306251881Speter} 307251881Speter 308251881Speter 309251881Spetersvn_error_t * 310251881Spetersvn_fs_base__unlock(svn_fs_t *fs, 311251881Speter const char *path, 312251881Speter const char *token, 313251881Speter svn_boolean_t break_lock, 314251881Speter apr_pool_t *pool) 315251881Speter{ 316251881Speter struct unlock_args args; 317251881Speter 318251881Speter SVN_ERR(svn_fs__check_fs(fs, TRUE)); 319251881Speter 320251881Speter args.path = svn_fs__canonicalize_abspath(path, pool); 321251881Speter args.token = token; 322251881Speter args.break_lock = break_lock; 323251881Speter return svn_fs_base__retry_txn(fs, txn_body_unlock, &args, TRUE, pool); 324251881Speter} 325251881Speter 326251881Speter 327251881Spetersvn_error_t * 328251881Spetersvn_fs_base__get_lock_helper(svn_lock_t **lock_p, 329251881Speter const char *path, 330251881Speter trail_t *trail, 331251881Speter apr_pool_t *pool) 332251881Speter{ 333251881Speter const char *lock_token; 334251881Speter svn_error_t *err; 335251881Speter 336251881Speter err = svn_fs_bdb__lock_token_get(&lock_token, trail->fs, path, 337251881Speter trail, pool); 338251881Speter 339251881Speter /* We've deliberately decided that this function doesn't tell the 340251881Speter caller *why* the lock is unavailable. */ 341251881Speter if (err && ((err->apr_err == SVN_ERR_FS_NO_SUCH_LOCK) 342251881Speter || (err->apr_err == SVN_ERR_FS_LOCK_EXPIRED) 343251881Speter || (err->apr_err == SVN_ERR_FS_BAD_LOCK_TOKEN))) 344251881Speter { 345251881Speter svn_error_clear(err); 346251881Speter *lock_p = NULL; 347251881Speter return SVN_NO_ERROR; 348251881Speter } 349251881Speter else 350251881Speter SVN_ERR(err); 351251881Speter 352251881Speter /* Same situation here. */ 353251881Speter err = svn_fs_bdb__lock_get(lock_p, trail->fs, lock_token, trail, pool); 354251881Speter if (err && ((err->apr_err == SVN_ERR_FS_LOCK_EXPIRED) 355251881Speter || (err->apr_err == SVN_ERR_FS_BAD_LOCK_TOKEN))) 356251881Speter { 357251881Speter svn_error_clear(err); 358251881Speter *lock_p = NULL; 359251881Speter return SVN_NO_ERROR; 360251881Speter } 361251881Speter else 362251881Speter SVN_ERR(err); 363251881Speter 364251881Speter return svn_error_trace(err); 365251881Speter} 366251881Speter 367251881Speter 368251881Speterstruct lock_token_get_args 369251881Speter{ 370251881Speter svn_lock_t **lock_p; 371251881Speter const char *path; 372251881Speter}; 373251881Speter 374251881Speter 375251881Speterstatic svn_error_t * 376251881Spetertxn_body_get_lock(void *baton, trail_t *trail) 377251881Speter{ 378251881Speter struct lock_token_get_args *args = baton; 379251881Speter return svn_fs_base__get_lock_helper(args->lock_p, args->path, 380251881Speter trail, trail->pool); 381251881Speter} 382251881Speter 383251881Speter 384251881Spetersvn_error_t * 385251881Spetersvn_fs_base__get_lock(svn_lock_t **lock, 386251881Speter svn_fs_t *fs, 387251881Speter const char *path, 388251881Speter apr_pool_t *pool) 389251881Speter{ 390251881Speter struct lock_token_get_args args; 391251881Speter 392251881Speter SVN_ERR(svn_fs__check_fs(fs, TRUE)); 393251881Speter 394251881Speter args.path = svn_fs__canonicalize_abspath(path, pool); 395251881Speter args.lock_p = lock; 396251881Speter return svn_fs_base__retry_txn(fs, txn_body_get_lock, &args, FALSE, pool); 397251881Speter} 398251881Speter 399251881Speter/* Implements `svn_fs_get_locks_callback_t', spooling lock information 400251881Speter to a stream as the filesystem provides it. BATON is an 'svn_stream_t *' 401251881Speter object pointing to the stream. We'll write the spool stream with a 402251881Speter format like so: 403251881Speter 404251881Speter SKEL1_LEN "\n" SKEL1 "\n" SKEL2_LEN "\n" SKEL2 "\n" ... 405251881Speter 406251881Speter where each skel is a lock skel (the same format we use to store 407251881Speter locks in the `locks' table). */ 408251881Speterstatic svn_error_t * 409251881Speterspool_locks_info(void *baton, 410251881Speter svn_lock_t *lock, 411251881Speter apr_pool_t *pool) 412251881Speter{ 413251881Speter svn_skel_t *lock_skel; 414251881Speter svn_stream_t *stream = baton; 415251881Speter const char *skel_len; 416251881Speter svn_stringbuf_t *skel_buf; 417251881Speter apr_size_t len; 418251881Speter 419251881Speter SVN_ERR(svn_fs_base__unparse_lock_skel(&lock_skel, lock, pool)); 420251881Speter skel_buf = svn_skel__unparse(lock_skel, pool); 421251881Speter skel_len = apr_psprintf(pool, "%" APR_SIZE_T_FMT "\n", skel_buf->len); 422251881Speter len = strlen(skel_len); 423251881Speter SVN_ERR(svn_stream_write(stream, skel_len, &len)); 424251881Speter len = skel_buf->len; 425251881Speter SVN_ERR(svn_stream_write(stream, skel_buf->data, &len)); 426251881Speter len = 1; 427251881Speter return svn_stream_write(stream, "\n", &len); 428251881Speter} 429251881Speter 430251881Speter 431251881Speterstruct locks_get_args 432251881Speter{ 433251881Speter const char *path; 434251881Speter svn_depth_t depth; 435251881Speter svn_stream_t *stream; 436251881Speter}; 437251881Speter 438251881Speter 439251881Speterstatic svn_error_t * 440251881Spetertxn_body_get_locks(void *baton, trail_t *trail) 441251881Speter{ 442251881Speter struct locks_get_args *args = baton; 443251881Speter return svn_fs_bdb__locks_get(trail->fs, args->path, args->depth, 444251881Speter spool_locks_info, args->stream, 445251881Speter trail, trail->pool); 446251881Speter} 447251881Speter 448251881Speter 449251881Spetersvn_error_t * 450251881Spetersvn_fs_base__get_locks(svn_fs_t *fs, 451251881Speter const char *path, 452251881Speter svn_depth_t depth, 453251881Speter svn_fs_get_locks_callback_t get_locks_func, 454251881Speter void *get_locks_baton, 455251881Speter apr_pool_t *pool) 456251881Speter{ 457251881Speter struct locks_get_args args; 458251881Speter svn_stream_t *stream; 459251881Speter svn_stringbuf_t *buf; 460251881Speter svn_boolean_t eof; 461251881Speter apr_pool_t *iterpool = svn_pool_create(pool); 462251881Speter 463251881Speter SVN_ERR(svn_fs__check_fs(fs, TRUE)); 464251881Speter 465251881Speter args.path = svn_fs__canonicalize_abspath(path, pool); 466251881Speter args.depth = depth; 467251881Speter /* Enough for 100+ locks if the comments are small. */ 468251881Speter args.stream = svn_stream__from_spillbuf(4 * 1024 /* blocksize */, 469251881Speter 64 * 1024 /* maxsize */, 470251881Speter pool); 471251881Speter SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_get_locks, &args, FALSE, pool)); 472251881Speter 473251881Speter /* Read the stream calling GET_LOCKS_FUNC(). */ 474251881Speter stream = args.stream; 475251881Speter 476251881Speter while (1) 477251881Speter { 478251881Speter apr_size_t len, skel_len; 479251881Speter char c, *skel_buf; 480251881Speter svn_skel_t *lock_skel; 481251881Speter svn_lock_t *lock; 482251881Speter apr_uint64_t ui64; 483251881Speter svn_error_t *err; 484251881Speter 485251881Speter svn_pool_clear(iterpool); 486251881Speter 487251881Speter /* Read a skel length line and parse it for the skel's length. */ 488251881Speter SVN_ERR(svn_stream_readline(stream, &buf, "\n", &eof, iterpool)); 489251881Speter if (eof) 490251881Speter break; 491251881Speter err = svn_cstring_strtoui64(&ui64, buf->data, 0, APR_SIZE_MAX, 10); 492251881Speter if (err) 493251881Speter return svn_error_create(SVN_ERR_MALFORMED_FILE, err, NULL); 494251881Speter skel_len = (apr_size_t)ui64; 495251881Speter 496251881Speter /* Now read that much into a buffer. */ 497251881Speter skel_buf = apr_palloc(pool, skel_len + 1); 498251881Speter SVN_ERR(svn_stream_read(stream, skel_buf, &skel_len)); 499251881Speter skel_buf[skel_len] = '\0'; 500251881Speter 501251881Speter /* Read the extra newline that follows the skel. */ 502251881Speter len = 1; 503251881Speter SVN_ERR(svn_stream_read(stream, &c, &len)); 504251881Speter if (c != '\n') 505251881Speter return svn_error_create(SVN_ERR_MALFORMED_FILE, NULL, NULL); 506251881Speter 507251881Speter /* Parse the skel into a lock, and notify the caller. */ 508251881Speter lock_skel = svn_skel__parse(skel_buf, skel_len, iterpool); 509251881Speter SVN_ERR(svn_fs_base__parse_lock_skel(&lock, lock_skel, iterpool)); 510251881Speter SVN_ERR(get_locks_func(get_locks_baton, lock, iterpool)); 511251881Speter } 512251881Speter 513251881Speter SVN_ERR(svn_stream_close(stream)); 514251881Speter svn_pool_destroy(iterpool); 515251881Speter return SVN_NO_ERROR; 516251881Speter} 517251881Speter 518251881Speter 519251881Speter 520251881Speter/* Utility function: verify that a lock can be used. 521251881Speter 522251881Speter If no username is attached to the FS, return SVN_ERR_FS_NO_USER. 523251881Speter 524251881Speter If the FS username doesn't match LOCK's owner, return 525251881Speter SVN_ERR_FS_LOCK_OWNER_MISMATCH. 526251881Speter 527251881Speter If FS hasn't been supplied with a matching lock-token for LOCK, 528251881Speter return SVN_ERR_FS_BAD_LOCK_TOKEN. 529251881Speter 530251881Speter Otherwise return SVN_NO_ERROR. 531251881Speter */ 532251881Speterstatic svn_error_t * 533251881Speterverify_lock(svn_fs_t *fs, 534251881Speter svn_lock_t *lock, 535251881Speter apr_pool_t *pool) 536251881Speter{ 537251881Speter if ((! fs->access_ctx) || (! fs->access_ctx->username)) 538251881Speter return svn_error_createf 539251881Speter (SVN_ERR_FS_NO_USER, NULL, 540251881Speter _("Cannot verify lock on path '%s'; no username available"), 541251881Speter lock->path); 542251881Speter 543251881Speter else if (strcmp(fs->access_ctx->username, lock->owner) != 0) 544251881Speter return svn_error_createf 545251881Speter (SVN_ERR_FS_LOCK_OWNER_MISMATCH, NULL, 546251881Speter _("User '%s' does not own lock on path '%s' (currently locked by '%s')"), 547251881Speter fs->access_ctx->username, lock->path, lock->owner); 548251881Speter 549251881Speter else if (svn_hash_gets(fs->access_ctx->lock_tokens, lock->token) == NULL) 550251881Speter return svn_error_createf 551251881Speter (SVN_ERR_FS_BAD_LOCK_TOKEN, NULL, 552251881Speter _("Cannot verify lock on path '%s'; no matching lock-token available"), 553251881Speter lock->path); 554251881Speter 555251881Speter return SVN_NO_ERROR; 556251881Speter} 557251881Speter 558251881Speter 559251881Speter/* This implements the svn_fs_get_locks_callback_t interface, where 560251881Speter BATON is just an svn_fs_t object. */ 561251881Speterstatic svn_error_t * 562251881Speterget_locks_callback(void *baton, 563251881Speter svn_lock_t *lock, 564251881Speter apr_pool_t *pool) 565251881Speter{ 566251881Speter return verify_lock(baton, lock, pool); 567251881Speter} 568251881Speter 569251881Speter 570251881Speter/* The main routine for lock enforcement, used throughout libsvn_fs_base. */ 571251881Spetersvn_error_t * 572251881Spetersvn_fs_base__allow_locked_operation(const char *path, 573251881Speter svn_boolean_t recurse, 574251881Speter trail_t *trail, 575251881Speter apr_pool_t *pool) 576251881Speter{ 577251881Speter if (recurse) 578251881Speter { 579251881Speter /* Discover all locks at or below the path. */ 580251881Speter SVN_ERR(svn_fs_bdb__locks_get(trail->fs, path, svn_depth_infinity, 581251881Speter get_locks_callback, 582251881Speter trail->fs, trail, pool)); 583251881Speter } 584251881Speter else 585251881Speter { 586251881Speter svn_lock_t *lock; 587251881Speter 588251881Speter /* Discover any lock attached to the path. */ 589251881Speter SVN_ERR(svn_fs_base__get_lock_helper(&lock, path, trail, pool)); 590251881Speter if (lock) 591251881Speter SVN_ERR(verify_lock(trail->fs, lock, pool)); 592251881Speter } 593251881Speter return SVN_NO_ERROR; 594251881Speter} 595