📄 lock.c
字号:
if ((val = hash_fetch(hash, EXPIRATION_DATE_KEY, pool))) SVN_ERR(svn_time_from_cstring(&(lock->expiration_date), val, pool)); lock->comment = hash_fetch(hash, COMMENT_KEY, pool); *lock_p = lock; } /* If our caller cares, see if we have any children for this path. */ val = hash_fetch(hash, CHILDREN_KEY, pool); if (val && children_p) { apr_array_header_t *kiddos = svn_cstring_split(val, "\n", FALSE, pool); int i; for (i = 0; i < kiddos->nelts; i++) { apr_hash_set(*children_p, APR_ARRAY_IDX(kiddos, i, const char *), APR_HASH_KEY_STRING, (void *)1); } } return SVN_NO_ERROR;}/*** Lock helper functions (path here are still FS paths, not on-disk schema-supporting paths) ***//* Write LOCK in FS to the actual OS filesystem. */static svn_error_t *set_lock(svn_fs_t *fs, svn_lock_t *lock, apr_pool_t *pool){ svn_stringbuf_t *this_path = svn_stringbuf_create(lock->path, pool); svn_stringbuf_t *last_child = svn_stringbuf_create("", pool); apr_pool_t *subpool; assert(lock); /* Iterate in reverse, creating the lock for LOCK->path, and then just adding entries for its parent, until we reach a parent that's already listed in *its* parent. */ subpool = svn_pool_create(pool); while (1729) { const char *digest_path, *parent_dir, *digest_file; apr_hash_t *this_children; svn_lock_t *this_lock; svn_pool_clear(subpool); /* Calculate the DIGEST_PATH for the currently FS path, and then split it into a PARENT_DIR and DIGEST_FILE basename. */ digest_path = digest_path_from_path(fs, this_path->data, subpool); svn_path_split(digest_path, &parent_dir, &digest_file, subpool); SVN_ERR(read_digest_file(&this_children, &this_lock, fs, digest_path, subpool)); /* We're either writing a new lock (first time through only) or a new entry (every time but the first). */ if (lock) { this_lock = lock; lock = NULL; svn_stringbuf_set(last_child, digest_file); } else { /* If we already have an entry for this path, we're done. */ if (apr_hash_get(this_children, last_child->data, last_child->len)) break; apr_hash_set(this_children, last_child->data, last_child->len, (void *)1); } SVN_ERR(write_digest_file(this_children, this_lock, fs, digest_path, subpool)); /* Prep for next iteration, or bail if we're done. */ if ((this_path->len == 1) && (this_path->data[0] == '/')) break; svn_stringbuf_set(this_path, svn_path_dirname(this_path->data, subpool)); } svn_pool_destroy(subpool); return SVN_NO_ERROR;}/* Delete LOCK from FS in the actual OS filesystem. */static svn_error_t *delete_lock(svn_fs_t *fs, svn_lock_t *lock, apr_pool_t *pool){ svn_stringbuf_t *this_path = svn_stringbuf_create(lock->path, pool); svn_stringbuf_t *child_to_kill = svn_stringbuf_create("", pool); apr_pool_t *subpool; assert(lock); /* Iterate in reverse, deleting the lock for LOCK->path, and then pruning entries from its parents. */ subpool = svn_pool_create(pool); while (1729) { const char *digest_path, *parent_dir, *digest_file; apr_hash_t *this_children; svn_lock_t *this_lock; svn_pool_clear(subpool); /* Calculate the DIGEST_PATH for the currently FS path, and then split it into a PARENT_DIR and DIGEST_FILE basename. */ digest_path = digest_path_from_path(fs, this_path->data, subpool); svn_path_split(digest_path, &parent_dir, &digest_file, subpool); SVN_ERR(read_digest_file(&this_children, &this_lock, fs, digest_path, subpool)); /* If we are supposed to drop the last entry from this path's children list, do so. */ if (child_to_kill->len) apr_hash_set(this_children, child_to_kill->data, child_to_kill->len, NULL); /* Delete the lock (first time through only). */ if (lock) { this_lock = NULL; lock = NULL; } if (! (this_lock || apr_hash_count(this_children) != 0)) { /* Special case: no goodz, no file. And remember to nix the entry for it in its parent. */ svn_stringbuf_set(child_to_kill, svn_path_basename(digest_path, subpool)); SVN_ERR(svn_io_remove_file(digest_path, subpool)); } else { SVN_ERR(write_digest_file(this_children, this_lock, fs, digest_path, subpool)); svn_stringbuf_setempty(child_to_kill); } /* Prep for next iteration, or bail if we're done. */ if ((this_path->len == 1) && (this_path->data[0] == '/')) break; svn_stringbuf_set(this_path, svn_path_dirname(this_path->data, subpool)); } svn_pool_destroy(subpool); return SVN_NO_ERROR;}/* Set *LOCK_P to the lock for PATH in FS. HAVE_WRITE_LOCK should be TRUE if the caller (or one of its callers) has taken out the repository-wide write lock, FALSE otherwise. Use POOL for allocations. */static svn_error_t *get_lock(svn_lock_t **lock_p, svn_fs_t *fs, const char *path, svn_boolean_t have_write_lock, apr_pool_t *pool){ svn_lock_t *lock; const char *digest_path = digest_path_from_path(fs, path, pool); SVN_ERR(read_digest_file(NULL, &lock, fs, digest_path, pool)); if (! lock) return svn_fs_fs__err_no_such_lock(fs, path); /* Don't return an expired lock. */ if (lock->expiration_date && (apr_time_now() > lock->expiration_date)) { /* Only remove the lock if we have the write lock. Read operations shouldn't change the filesystem. */ if (have_write_lock) SVN_ERR(delete_lock(fs, lock, pool)); *lock_p = NULL; return svn_fs_fs__err_lock_expired(fs, lock->token); } *lock_p = lock; return SVN_NO_ERROR;}/* Set *LOCK_P to the lock for PATH in FS. HAVE_WRITE_LOCK should be TRUE if the caller (or one of its callers) has taken out the repository-wide write lock, FALSE otherwise. Use POOL for allocations. */static svn_error_t *get_lock_helper(svn_fs_t *fs, svn_lock_t **lock_p, const char *path, svn_boolean_t have_write_lock, apr_pool_t *pool){ svn_lock_t *lock; svn_error_t *err; err = get_lock(&lock, fs, path, have_write_lock, pool); /* We've deliberately decided that this function doesn't tell the caller *why* the lock is unavailable. */ if (err && ((err->apr_err == SVN_ERR_FS_NO_SUCH_LOCK) || (err->apr_err == SVN_ERR_FS_LOCK_EXPIRED))) { svn_error_clear(err); *lock_p = NULL; return SVN_NO_ERROR; } else SVN_ERR(err); *lock_p = lock; return SVN_NO_ERROR;}/* A recursive function that calls GET_LOCKS_FUNC/GET_LOCKS_BATON for all locks in and under PATH in FS. HAVE_WRITE_LOCK should be true if the caller (directly or indirectly) has the FS write lock. */static svn_error_t *walk_digest_files(svn_fs_t *fs, const char *digest_path, svn_fs_get_locks_callback_t get_locks_func, void *get_locks_baton, svn_boolean_t have_write_lock, apr_pool_t *pool){ apr_hash_t *children; svn_lock_t *lock; apr_hash_index_t *hi; apr_pool_t *subpool; /* First, send up any locks in the current digest file. */ SVN_ERR(read_digest_file(&children, &lock, fs, digest_path, pool)); if (lock) { /* Don't report an expired lock. */ if (lock->expiration_date == 0 || (apr_time_now() <= lock->expiration_date)) { if (get_locks_func) SVN_ERR(get_locks_func(get_locks_baton, lock, pool)); } else { /* Only remove the lock if we have the write lock. Read operations shouldn't change the filesystem. */ if (have_write_lock) SVN_ERR(delete_lock(fs, lock, pool)); } } /* Now, recurse on this thing's child entries (if any; bail otherwise). */ if (! apr_hash_count(children)) return SVN_NO_ERROR; subpool = svn_pool_create(pool); for (hi = apr_hash_first(pool, children); hi; hi = apr_hash_next(hi)) { const void *key; svn_pool_clear(subpool); apr_hash_this(hi, &key, NULL, NULL); SVN_ERR(walk_digest_files (fs, digest_path_from_digest(fs, key, subpool), get_locks_func, get_locks_baton, have_write_lock, subpool)); } svn_pool_destroy(subpool); return SVN_NO_ERROR;}/* Utility function: verify that a lock can be used. Interesting errors returned from this function: SVN_ERR_FS_NO_USER: No username attached to FS. SVN_ERR_FS_LOCK_OWNER_MISMATCH: FS's username doesn't match LOCK's owner. SVN_ERR_FS_BAD_LOCK_TOKEN: FS doesn't hold matching lock-token for LOCK. */static svn_error_t *verify_lock(svn_fs_t *fs, svn_lock_t *lock, apr_pool_t *pool){ if ((! fs->access_ctx) || (! fs->access_ctx->username)) return svn_error_createf (SVN_ERR_FS_NO_USER, NULL, _("Cannot verify lock on path '%s'; no username available"), lock->path); else if (strcmp(fs->access_ctx->username, lock->owner) != 0) return svn_error_createf (SVN_ERR_FS_LOCK_OWNER_MISMATCH, NULL, _("User %s does not own lock on path '%s' (currently locked by %s)"), fs->access_ctx->username, lock->path, lock->owner); else if (apr_hash_get(fs->access_ctx->lock_tokens, lock->token, APR_HASH_KEY_STRING) == NULL) return svn_error_createf (SVN_ERR_FS_BAD_LOCK_TOKEN, NULL, _("Cannot verify lock on path '%s'; no matching lock-token available"), lock->path);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -