📄 lock.c
字号:
return SVN_NO_ERROR;}/* This implements the svn_fs_get_locks_callback_t interface, where BATON is just an svn_fs_t object. */static svn_error_t *get_locks_callback(void *baton, svn_lock_t *lock, apr_pool_t *pool){ return verify_lock(baton, lock, pool);}/* The main routine for lock enforcement, used throughout libsvn_fs_fs. */svn_error_t *svn_fs_fs__allow_locked_operation(const char *path, svn_fs_t *fs, svn_boolean_t recurse, svn_boolean_t have_write_lock, apr_pool_t *pool){ path = svn_fs_fs__canonicalize_abspath(path, pool); if (recurse) { /* Discover all locks at or below the path. */ const char *digest_path = digest_path_from_path(fs, path, pool); SVN_ERR(walk_digest_files(fs, digest_path, get_locks_callback, fs, have_write_lock, pool)); } else { /* Discover and verify any lock attached to the path. */ svn_lock_t *lock; SVN_ERR(get_lock_helper(fs, &lock, path, have_write_lock, pool)); if (lock) SVN_ERR(verify_lock(fs, lock, pool)); } return SVN_NO_ERROR;}/* Baton used for lock_body below. */struct lock_baton { svn_lock_t **lock_p; svn_fs_t *fs; const char *path; const char *token; const char *comment; svn_boolean_t is_dav_comment; apr_time_t expiration_date; svn_revnum_t current_rev; svn_boolean_t steal_lock; apr_pool_t *pool;};/* This implements the svn_fs_fs__with_write_lock() 'body' callback type, and assumes that the write lock is held. BATON is a 'struct lock_baton *'. */static svn_error_t *lock_body(void *baton, apr_pool_t *pool){ struct lock_baton *lb = baton; svn_node_kind_t kind; svn_lock_t *existing_lock; svn_lock_t *lock; svn_fs_root_t *root; svn_revnum_t youngest; /* Until we implement directory locks someday, we only allow locks on files or non-existent paths. */ /* Use fs->vtable->foo instead of svn_fs_foo to avoid circular library dependencies, which are not portable. */ SVN_ERR(lb->fs->vtable->youngest_rev(&youngest, lb->fs, pool)); SVN_ERR(lb->fs->vtable->revision_root(&root, lb->fs, youngest, pool)); SVN_ERR(svn_fs_fs__check_path(&kind, root, lb->path, pool)); if (kind == svn_node_dir) return svn_fs_fs__err_not_file(lb->fs, lb->path); /* While our locking implementation easily supports the locking of nonexistent paths, we deliberately choose not to allow such madness. */ if (kind == svn_node_none) return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL, _("Path '%s' doesn't exist in HEAD revision"), lb->path); /* We need to have a username attached to the fs. */ if (!lb->fs->access_ctx || !lb->fs->access_ctx->username) return svn_fs_fs__err_no_user(lb->fs); /* Is the caller attempting to lock an out-of-date working file? */ if (SVN_IS_VALID_REVNUM(lb->current_rev)) { svn_revnum_t created_rev; SVN_ERR(svn_fs_fs__node_created_rev(&created_rev, root, lb->path, pool)); /* SVN_INVALID_REVNUM means the path doesn't exist. So apparently somebody is trying to lock something in their working copy, but somebody else has deleted the thing from HEAD. That counts as being 'out of date'. */ if (! SVN_IS_VALID_REVNUM(created_rev)) return svn_error_createf (SVN_ERR_FS_OUT_OF_DATE, NULL, _("Path '%s' doesn't exist in HEAD revision"), lb->path); if (lb->current_rev < created_rev) return svn_error_createf (SVN_ERR_FS_OUT_OF_DATE, NULL, _("Lock failed: newer version of '%s' exists"), lb->path); } /* If the caller provided a TOKEN, we *really* need to see if a lock already exists with that token, and if so, verify that the lock's path matches PATH. Otherwise we run the risk of breaking the 1-to-1 mapping of lock tokens to locked paths. */ /* ### TODO: actually do this check. This is tough, because the schema doesn't supply a lookup-by-token mechanism. */ /* Is the path already locked? Note that this next function call will automatically ignore any errors about {the path not existing as a key, the path's token not existing as a key, the lock just having been expired}. And that's totally fine. Any of these three errors are perfectly acceptable to ignore; it means that the path is now free and clear for locking, because the fsfs funcs just cleared out both of the tables for us. */ SVN_ERR(get_lock_helper(lb->fs, &existing_lock, lb->path, TRUE, pool)); if (existing_lock) { if (! lb->steal_lock) { /* Sorry, the path is already locked. */ return svn_fs_fs__err_path_already_locked(lb->fs, existing_lock); } else { /* STEAL_LOCK was passed, so fs_username is "stealing" the lock from lock->owner. Destroy the existing lock. */ SVN_ERR(delete_lock(lb->fs, existing_lock, pool)); } } /* Create our new lock, and add it to the tables. Ensure that the lock is created in the correct pool. */ lock = svn_lock_create(lb->pool); if (lb->token) lock->token = apr_pstrdup(lb->pool, lb->token); else SVN_ERR(svn_fs_fs__generate_lock_token(&(lock->token), lb->fs, lb->pool)); lock->path = apr_pstrdup(lb->pool, lb->path); lock->owner = apr_pstrdup(lb->pool, lb->fs->access_ctx->username); lock->comment = apr_pstrdup(lb->pool, lb->comment); lock->is_dav_comment = lb->is_dav_comment; lock->creation_date = apr_time_now(); lock->expiration_date = lb->expiration_date; SVN_ERR(set_lock(lb->fs, lock, pool)); *lb->lock_p = lock; return SVN_NO_ERROR;}/* Baton used for unlock_body below. */struct unlock_baton { svn_fs_t *fs; const char *path; const char *token; svn_boolean_t break_lock;};/* This implements the svn_fs_fs__with_write_lock() 'body' callback type, and assumes that the write lock is held. BATON is a 'struct unlock_baton *'. */static svn_error_t *unlock_body(void *baton, apr_pool_t *pool){ struct unlock_baton *ub = baton; svn_lock_t *lock; /* This could return SVN_ERR_FS_BAD_LOCK_TOKEN or SVN_ERR_FS_LOCK_EXPIRED. */ SVN_ERR(get_lock(&lock, ub->fs, ub->path, TRUE, pool)); /* Unless breaking the lock, we do some checks. */ if (! ub->break_lock) { /* Sanity check: the incoming token should match lock->token. */ if (strcmp(ub->token, lock->token) != 0) return svn_fs_fs__err_no_such_lock(ub->fs, lock->path); /* There better be a username attached to the fs. */ if (! (ub->fs->access_ctx && ub->fs->access_ctx->username)) return svn_fs_fs__err_no_user(ub->fs); /* And that username better be the same as the lock's owner. */ if (strcmp(ub->fs->access_ctx->username, lock->owner) != 0) return svn_fs_fs__err_lock_owner_mismatch (ub->fs, ub->fs->access_ctx->username, lock->owner); } /* Remove lock and lock token files. */ SVN_ERR(delete_lock(ub->fs, lock, pool)); return SVN_NO_ERROR;}/*** Public API implementations ***/svn_error_t *svn_fs_fs__lock(svn_lock_t **lock_p, svn_fs_t *fs, const char *path, const char *token, const char *comment, svn_boolean_t is_dav_comment, apr_time_t expiration_date, svn_revnum_t current_rev, svn_boolean_t steal_lock, apr_pool_t *pool){ struct lock_baton lb; SVN_ERR(svn_fs_fs__check_fs(fs)); path = svn_fs_fs__canonicalize_abspath(path, pool); lb.lock_p = lock_p; lb.fs = fs; lb.path = path; lb.token = token; lb.comment = comment; lb.is_dav_comment = is_dav_comment; lb.expiration_date = expiration_date; lb.current_rev = current_rev; lb.steal_lock = steal_lock; lb.pool = pool; SVN_ERR(svn_fs_fs__with_write_lock(fs, lock_body, &lb, pool)); return SVN_NO_ERROR;}svn_error_t *svn_fs_fs__generate_lock_token(const char **token, svn_fs_t *fs, apr_pool_t *pool){ SVN_ERR(svn_fs_fs__check_fs(fs)); /* Notice that 'fs' is currently unused. But perhaps someday, we'll want to use the fs UUID + some incremented number? For now, we generate a URI that matches the DAV RFC. We could change this to some other URI scheme someday, if we wish. */ *token = apr_pstrcat(pool, "opaquelocktoken:", svn_uuid_generate(pool), NULL); return SVN_NO_ERROR;}svn_error_t *svn_fs_fs__unlock(svn_fs_t *fs, const char *path, const char *token, svn_boolean_t break_lock, apr_pool_t *pool){ struct unlock_baton ub; SVN_ERR(svn_fs_fs__check_fs(fs)); path = svn_fs_fs__canonicalize_abspath(path, pool); ub.fs = fs; ub.path = path; ub.token = token; ub.break_lock = break_lock; SVN_ERR(svn_fs_fs__with_write_lock(fs, unlock_body, &ub, pool)); return SVN_NO_ERROR;}svn_error_t *svn_fs_fs__get_lock(svn_lock_t **lock_p, svn_fs_t *fs, const char *path, apr_pool_t *pool){ SVN_ERR(svn_fs_fs__check_fs(fs)); path = svn_fs_fs__canonicalize_abspath(path, pool); return get_lock_helper(fs, lock_p, path, FALSE, pool);}svn_error_t *svn_fs_fs__get_locks(svn_fs_t *fs, const char *path, svn_fs_get_locks_callback_t get_locks_func, void *get_locks_baton, apr_pool_t *pool){ const char *digest_path; SVN_ERR(svn_fs_fs__check_fs(fs)); path = svn_fs_fs__canonicalize_abspath(path, pool); /* Get the top digest path in our tree of interest, and then walk it. */ digest_path = digest_path_from_path(fs, path, pool); return walk_digest_files(fs, digest_path, get_locks_func, get_locks_baton, FALSE, pool);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -