1251881Speter/* locks-table.c : operations on the `locks' table 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#include <string.h> 24251881Speter#include <assert.h> 25251881Speter 26251881Speter#include "bdb_compat.h" 27251881Speter 28251881Speter#include "svn_pools.h" 29251881Speter#include "svn_path.h" 30251881Speter#include "private/svn_skel.h" 31251881Speter 32251881Speter#include "dbt.h" 33251881Speter#include "../err.h" 34251881Speter#include "../fs.h" 35251881Speter#include "../util/fs_skels.h" 36251881Speter#include "../trail.h" 37251881Speter#include "../../libsvn_fs/fs-loader.h" 38251881Speter#include "bdb-err.h" 39251881Speter#include "locks-table.h" 40251881Speter#include "lock-tokens-table.h" 41251881Speter 42251881Speter#include "private/svn_fs_util.h" 43251881Speter#include "private/svn_fspath.h" 44251881Speter 45251881Speter 46251881Speterint 47251881Spetersvn_fs_bdb__open_locks_table(DB **locks_p, 48251881Speter DB_ENV *env, 49251881Speter svn_boolean_t create) 50251881Speter{ 51251881Speter const u_int32_t open_flags = (create ? (DB_CREATE | DB_EXCL) : 0); 52251881Speter DB *locks; 53251881Speter int error; 54251881Speter 55251881Speter BDB_ERR(svn_fs_bdb__check_version()); 56251881Speter BDB_ERR(db_create(&locks, env, 0)); 57251881Speter error = (locks->open)(SVN_BDB_OPEN_PARAMS(locks, NULL), 58251881Speter "locks", 0, DB_BTREE, 59251881Speter open_flags, 0666); 60251881Speter 61251881Speter /* Create the table if it doesn't yet exist. This is a form of 62251881Speter automagical repository upgrading. */ 63251881Speter if (error == ENOENT && (! create)) 64251881Speter { 65251881Speter BDB_ERR(locks->close(locks, 0)); 66251881Speter return svn_fs_bdb__open_locks_table(locks_p, env, TRUE); 67251881Speter } 68251881Speter BDB_ERR(error); 69251881Speter 70251881Speter *locks_p = locks; 71251881Speter return 0; 72251881Speter} 73251881Speter 74251881Speter 75251881Speter 76251881Spetersvn_error_t * 77251881Spetersvn_fs_bdb__lock_add(svn_fs_t *fs, 78251881Speter const char *lock_token, 79251881Speter svn_lock_t *lock, 80251881Speter trail_t *trail, 81251881Speter apr_pool_t *pool) 82251881Speter{ 83251881Speter base_fs_data_t *bfd = fs->fsap_data; 84251881Speter svn_skel_t *lock_skel; 85251881Speter DBT key, value; 86251881Speter 87251881Speter /* Convert native type to skel. */ 88251881Speter SVN_ERR(svn_fs_base__unparse_lock_skel(&lock_skel, lock, pool)); 89251881Speter 90251881Speter svn_fs_base__str_to_dbt(&key, lock_token); 91251881Speter svn_fs_base__skel_to_dbt(&value, lock_skel, pool); 92251881Speter svn_fs_base__trail_debug(trail, "lock", "add"); 93251881Speter return BDB_WRAP(fs, N_("storing lock record"), 94251881Speter bfd->locks->put(bfd->locks, trail->db_txn, 95251881Speter &key, &value, 0)); 96251881Speter} 97251881Speter 98251881Speter 99251881Speter 100251881Spetersvn_error_t * 101251881Spetersvn_fs_bdb__lock_delete(svn_fs_t *fs, 102251881Speter const char *lock_token, 103251881Speter trail_t *trail, 104251881Speter apr_pool_t *pool) 105251881Speter{ 106251881Speter base_fs_data_t *bfd = fs->fsap_data; 107251881Speter DBT key; 108251881Speter int db_err; 109251881Speter 110251881Speter svn_fs_base__str_to_dbt(&key, lock_token); 111251881Speter svn_fs_base__trail_debug(trail, "locks", "del"); 112251881Speter db_err = bfd->locks->del(bfd->locks, trail->db_txn, &key, 0); 113251881Speter 114251881Speter if (db_err == DB_NOTFOUND) 115251881Speter return svn_fs_base__err_bad_lock_token(fs, lock_token); 116251881Speter return BDB_WRAP(fs, N_("deleting lock from 'locks' table"), db_err); 117251881Speter} 118251881Speter 119251881Speter 120251881Speter 121251881Spetersvn_error_t * 122251881Spetersvn_fs_bdb__lock_get(svn_lock_t **lock_p, 123251881Speter svn_fs_t *fs, 124251881Speter const char *lock_token, 125251881Speter trail_t *trail, 126251881Speter apr_pool_t *pool) 127251881Speter{ 128251881Speter base_fs_data_t *bfd = fs->fsap_data; 129251881Speter DBT key, value; 130251881Speter int db_err; 131251881Speter svn_skel_t *skel; 132251881Speter svn_lock_t *lock; 133251881Speter 134251881Speter svn_fs_base__trail_debug(trail, "lock", "get"); 135251881Speter db_err = bfd->locks->get(bfd->locks, trail->db_txn, 136251881Speter svn_fs_base__str_to_dbt(&key, lock_token), 137251881Speter svn_fs_base__result_dbt(&value), 138251881Speter 0); 139251881Speter svn_fs_base__track_dbt(&value, pool); 140251881Speter 141251881Speter if (db_err == DB_NOTFOUND) 142251881Speter return svn_fs_base__err_bad_lock_token(fs, lock_token); 143251881Speter SVN_ERR(BDB_WRAP(fs, N_("reading lock"), db_err)); 144251881Speter 145251881Speter /* Parse TRANSACTION skel */ 146251881Speter skel = svn_skel__parse(value.data, value.size, pool); 147251881Speter if (! skel) 148251881Speter return svn_fs_base__err_corrupt_lock(fs, lock_token); 149251881Speter 150251881Speter /* Convert skel to native type. */ 151251881Speter SVN_ERR(svn_fs_base__parse_lock_skel(&lock, skel, pool)); 152251881Speter 153251881Speter /* Possibly auto-expire the lock. */ 154251881Speter if (lock->expiration_date && (apr_time_now() > lock->expiration_date)) 155251881Speter { 156251881Speter SVN_ERR(svn_fs_bdb__lock_delete(fs, lock_token, trail, pool)); 157251881Speter return SVN_FS__ERR_LOCK_EXPIRED(fs, lock_token); 158251881Speter } 159251881Speter 160251881Speter *lock_p = lock; 161251881Speter return SVN_NO_ERROR; 162251881Speter} 163251881Speter 164251881Speter 165251881Speterstatic svn_error_t * 166251881Speterget_lock(svn_lock_t **lock_p, 167251881Speter svn_fs_t *fs, 168251881Speter const char *path, 169251881Speter const char *lock_token, 170251881Speter trail_t *trail, 171251881Speter apr_pool_t *pool) 172251881Speter{ 173251881Speter svn_error_t *err = SVN_NO_ERROR; 174251881Speter *lock_p = NULL; 175251881Speter 176251881Speter /* Make sure the token points to an existing, non-expired lock, by 177251881Speter doing a lookup in the `locks' table. Use 'pool'. */ 178251881Speter err = svn_fs_bdb__lock_get(lock_p, fs, lock_token, trail, pool); 179251881Speter if (err && ((err->apr_err == SVN_ERR_FS_LOCK_EXPIRED) 180251881Speter || (err->apr_err == SVN_ERR_FS_BAD_LOCK_TOKEN))) 181251881Speter { 182251881Speter svn_error_clear(err); 183251881Speter 184251881Speter /* If `locks' doesn't have the lock, then we should lose it 185251881Speter from `lock-tokens' table as well, then skip to the next 186251881Speter matching path-key. */ 187251881Speter err = svn_fs_bdb__lock_token_delete(fs, path, trail, pool); 188251881Speter } 189251881Speter return svn_error_trace(err); 190251881Speter} 191251881Speter 192251881Speter 193251881Spetersvn_error_t * 194251881Spetersvn_fs_bdb__locks_get(svn_fs_t *fs, 195251881Speter const char *path, 196251881Speter svn_depth_t depth, 197251881Speter svn_fs_get_locks_callback_t get_locks_func, 198251881Speter void *get_locks_baton, 199251881Speter trail_t *trail, 200251881Speter apr_pool_t *pool) 201251881Speter{ 202251881Speter base_fs_data_t *bfd = fs->fsap_data; 203251881Speter DBC *cursor; 204251881Speter DBT key, value; 205251881Speter int db_err, db_c_err; 206251881Speter apr_pool_t *subpool = svn_pool_create(pool); 207251881Speter const char *lock_token; 208251881Speter svn_lock_t *lock; 209251881Speter svn_error_t *err; 210251881Speter const char *lookup_path = path; 211251881Speter apr_size_t lookup_len; 212251881Speter 213251881Speter /* First, try to lookup PATH itself. */ 214251881Speter err = svn_fs_bdb__lock_token_get(&lock_token, fs, path, trail, pool); 215251881Speter if (err && ((err->apr_err == SVN_ERR_FS_LOCK_EXPIRED) 216251881Speter || (err->apr_err == SVN_ERR_FS_BAD_LOCK_TOKEN) 217251881Speter || (err->apr_err == SVN_ERR_FS_NO_SUCH_LOCK))) 218251881Speter { 219251881Speter svn_error_clear(err); 220251881Speter } 221251881Speter else if (err) 222251881Speter { 223251881Speter return svn_error_trace(err); 224251881Speter } 225251881Speter else 226251881Speter { 227251881Speter SVN_ERR(get_lock(&lock, fs, path, lock_token, trail, pool)); 228251881Speter if (lock && get_locks_func) 229251881Speter { 230251881Speter SVN_ERR(get_locks_func(get_locks_baton, lock, pool)); 231251881Speter 232251881Speter /* Found a lock so PATH is a file and we can ignore depth */ 233251881Speter return SVN_NO_ERROR; 234251881Speter } 235251881Speter } 236251881Speter 237251881Speter /* If we're only looking at PATH itself (depth = empty), stop here. */ 238251881Speter if (depth == svn_depth_empty) 239251881Speter return SVN_NO_ERROR; 240251881Speter 241251881Speter /* Now go hunt for possible children of PATH. */ 242251881Speter 243251881Speter svn_fs_base__trail_debug(trail, "lock-tokens", "cursor"); 244251881Speter db_err = bfd->lock_tokens->cursor(bfd->lock_tokens, trail->db_txn, 245251881Speter &cursor, 0); 246251881Speter SVN_ERR(BDB_WRAP(fs, N_("creating cursor for reading lock tokens"), 247251881Speter db_err)); 248251881Speter 249251881Speter /* Since the key is going to be returned as well as the value make 250251881Speter sure BDB malloc's the returned key. */ 251251881Speter svn_fs_base__str_to_dbt(&key, lookup_path); 252251881Speter key.flags |= DB_DBT_MALLOC; 253251881Speter 254251881Speter /* Get the first matching key that is either equal or greater than 255251881Speter the one passed in, by passing in the DB_RANGE_SET flag. */ 256251881Speter db_err = svn_bdb_dbc_get(cursor, &key, svn_fs_base__result_dbt(&value), 257251881Speter DB_SET_RANGE); 258251881Speter 259251881Speter if (!svn_fspath__is_root(path, strlen(path))) 260251881Speter lookup_path = apr_pstrcat(pool, path, "/", (char *)NULL); 261251881Speter lookup_len = strlen(lookup_path); 262251881Speter 263251881Speter /* As long as the prefix of the returned KEY matches LOOKUP_PATH we 264251881Speter know it is either LOOKUP_PATH or a decendant thereof. */ 265251881Speter while ((! db_err) 266251881Speter && lookup_len < key.size 267251881Speter && strncmp(lookup_path, key.data, lookup_len) == 0) 268251881Speter { 269251881Speter const char *child_path; 270251881Speter 271251881Speter svn_pool_clear(subpool); 272251881Speter 273251881Speter svn_fs_base__track_dbt(&key, subpool); 274251881Speter svn_fs_base__track_dbt(&value, subpool); 275251881Speter 276251881Speter /* Create a usable path and token in temporary memory. */ 277251881Speter child_path = apr_pstrmemdup(subpool, key.data, key.size); 278251881Speter lock_token = apr_pstrmemdup(subpool, value.data, value.size); 279251881Speter 280251881Speter if ((depth == svn_depth_files) || (depth == svn_depth_immediates)) 281251881Speter { 282251881Speter /* On the assumption that we only store locks for files, 283251881Speter depth=files and depth=immediates should boil down to the 284251881Speter same set of results. So just see if CHILD_PATH is an 285251881Speter immediate child of PATH. If not, we don't care about 286251881Speter this item. */ 287251881Speter const char *rel_path = svn_fspath__skip_ancestor(path, child_path); 288251881Speter if (!rel_path || (svn_path_component_count(rel_path) != 1)) 289251881Speter goto loop_it; 290251881Speter } 291251881Speter 292251881Speter /* Get the lock for CHILD_PATH. */ 293251881Speter err = get_lock(&lock, fs, child_path, lock_token, trail, subpool); 294251881Speter if (err) 295251881Speter { 296251881Speter svn_bdb_dbc_close(cursor); 297251881Speter return svn_error_trace(err); 298251881Speter } 299251881Speter 300251881Speter /* Lock is verified, hand it off to our callback. */ 301251881Speter if (lock && get_locks_func) 302251881Speter { 303251881Speter err = get_locks_func(get_locks_baton, lock, subpool); 304251881Speter if (err) 305251881Speter { 306251881Speter svn_bdb_dbc_close(cursor); 307251881Speter return svn_error_trace(err); 308251881Speter } 309251881Speter } 310251881Speter 311251881Speter loop_it: 312251881Speter svn_fs_base__result_dbt(&key); 313251881Speter svn_fs_base__result_dbt(&value); 314251881Speter db_err = svn_bdb_dbc_get(cursor, &key, &value, DB_NEXT); 315251881Speter } 316251881Speter 317251881Speter svn_pool_destroy(subpool); 318251881Speter db_c_err = svn_bdb_dbc_close(cursor); 319251881Speter 320251881Speter if (db_err && (db_err != DB_NOTFOUND)) 321251881Speter SVN_ERR(BDB_WRAP(fs, N_("fetching lock tokens"), db_err)); 322251881Speter if (db_c_err) 323251881Speter SVN_ERR(BDB_WRAP(fs, N_("fetching lock tokens (closing cursor)"), 324251881Speter db_c_err)); 325251881Speter 326251881Speter return SVN_NO_ERROR; 327251881Speter} 328251881Speter 329