📄 lock.c
字号:
dav_svn_append_locks(dav_lockdb *lockdb, const dav_resource *resource, int make_indirect, const dav_lock *lock){ dav_lockdb_private *info = lockdb->info; svn_lock_t *slock; svn_error_t *serr; dav_error *derr; svn_boolean_t readable = FALSE; /* If the resource's fs path is unreadable, we don't allow a lock to be created on it. */ derr = check_readability(&readable, resource->info->r, resource->info->repos, resource->info->repos_path, resource->pool); if (derr) return derr; if (! readable) return dav_new_error(resource->pool, HTTP_FORBIDDEN, DAV_ERR_LOCK_SAVE_LOCK, "Path is not accessible."); if (lock->next) return dav_new_error(resource->pool, HTTP_BAD_REQUEST, DAV_ERR_LOCK_SAVE_LOCK, "Tried to attach multiple locks to a resource."); /* RFC2518bis (section 7.4) doesn't require us to support 'lock-null' resources at all. Instead, it asks that we treat 'LOCK nonexistentURL' as a PUT (followed by a LOCK) of a 0-byte file. */ if (! resource->exists) { svn_revnum_t rev, new_rev; svn_fs_txn_t *txn; svn_fs_root_t *txn_root; const char *conflict_msg; dav_svn_repos *repos = resource->info->repos; if (resource->info->repos->is_svn_client) return dav_new_error(resource->pool, HTTP_METHOD_NOT_ALLOWED, DAV_ERR_LOCK_SAVE_LOCK, "Subversion clients may not lock " "nonexistent paths."); else if (! resource->info->repos->autoversioning) return dav_new_error(resource->pool, HTTP_METHOD_NOT_ALLOWED, DAV_ERR_LOCK_SAVE_LOCK, "Attempted to lock non-existent path;" " turn on autoversioning first."); /* Commit a 0-byte file: */ if ((serr = svn_fs_youngest_rev(&rev, repos->fs, resource->pool))) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not determine youngest revision", resource->pool); if ((serr = svn_repos_fs_begin_txn_for_commit(&txn, repos->repos, rev, repos->username, NULL, resource->pool))) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not begin a transaction", resource->pool); if ((serr = svn_fs_txn_root(&txn_root, txn, resource->pool))) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not begin a transaction", resource->pool); if ((serr = svn_fs_make_file(txn_root, resource->info->repos_path, resource->pool))) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not create empty file.", resource->pool); if ((serr = dav_svn_attach_auto_revprops(txn, resource->info->repos_path, resource->pool))) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Could not create empty file.", resource->pool); if ((serr = svn_repos_fs_commit_txn(&conflict_msg, repos->repos, &new_rev, txn, resource->pool))) { svn_error_clear(svn_fs_abort_txn(txn, resource->pool)); return dav_svn_convert_err(serr, HTTP_CONFLICT, apr_psprintf(resource->pool, "Conflict when committing " "'%s'.", conflict_msg), resource->pool); } } /* Convert the dav_lock into an svn_lock_t. */ derr = dav_lock_to_svn_lock(&slock, lock, resource->info->repos_path, info, resource->info->repos->is_svn_client, resource->pool); if (derr) return derr; /* Now use the svn_lock_t to actually perform the lock. */ serr = svn_repos_fs_lock(&slock, resource->info->repos->repos, slock->path, slock->token, slock->comment, slock->is_dav_comment, slock->expiration_date, info->working_revnum, info->lock_steal, resource->pool); if (serr && serr->apr_err == SVN_ERR_FS_NO_USER) return dav_new_error(resource->pool, HTTP_UNAUTHORIZED, DAV_ERR_LOCK_SAVE_LOCK, "Anonymous lock creation is not allowed."); else if (serr) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to create new lock.", resource->pool); /* A standard webdav LOCK response doesn't include any information about the creation date. We send it in a custom header, so that svn clients can fill in svn_lock_t->creation_date. A generic DAV client should just ignore the header. */ apr_table_setn(info->r->headers_out, SVN_DAV_CREATIONDATE_HEADER, svn_time_to_cstring(slock->creation_date, resource->pool)); /* A standard webdav LOCK response doesn't include any information about the owner of the lock. ('DAV:owner' has nothing to do with authorization, it's just a comment that we map to svn_lock_t->comment.) We send the owner in a custom header, so that svn clients can fill in svn_lock_t->owner. A generic DAV client should just ignore the header. */ apr_table_setn(info->r->headers_out, SVN_DAV_LOCK_OWNER_HEADER, slock->owner); /* Log the locking as a 'high-level' action. */ apr_table_set(resource->info->r->subprocess_env, "SVN-ACTION", apr_psprintf(resource->info->r->pool, "lock '%s'", svn_path_uri_encode(slock->path, resource->info->r->pool))); return 0;}/*** Remove any lock that has the specified locktoken.**** If locktoken == NULL, then ALL locks are removed.*/static dav_error *dav_svn_remove_lock(dav_lockdb *lockdb, const dav_resource *resource, const dav_locktoken *locktoken){ dav_lockdb_private *info = lockdb->info; svn_error_t *serr; dav_error *derr; svn_boolean_t readable = FALSE; svn_lock_t *slock; const char *token = NULL; /* Sanity check: if the resource has no associated path in the fs, then there's nothing to do. */ if (! resource->info->repos_path) return 0; /* Another easy out: if an svn client sent a 'keep_locks' header (typically in a DELETE request, as part of 'svn commit --no-unlock'), then ignore dav_method_delete()'s attempt to unconditionally remove the lock. */ if (info->keep_locks) return 0; /* If the resource's fs path is unreadable, we don't allow a lock to be removed from it. */ derr = check_readability(&readable, resource->info->r, resource->info->repos, resource->info->repos_path, resource->pool); if (derr) return derr; if (! readable) return dav_new_error(resource->pool, HTTP_FORBIDDEN, DAV_ERR_LOCK_SAVE_LOCK, "Path is not accessible."); if (locktoken == NULL) { /* Need to manually discover any lock on the resource. */ serr = svn_fs_get_lock(&slock, resource->info->repos->fs, resource->info->repos_path, resource->pool); if (serr) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to check path for a lock.", resource->pool); if (slock) token = slock->token; } else { token = locktoken->uuid_str; } if (token) { /* Notice that a generic DAV client is unable to forcibly 'break' a lock, because info->lock_break will always be FALSE. An svn client, however, can request a 'forced' break.*/ serr = svn_repos_fs_unlock(resource->info->repos->repos, resource->info->repos_path, token, info->lock_break, resource->pool); if (serr && serr->apr_err == SVN_ERR_FS_NO_USER) return dav_new_error(resource->pool, HTTP_UNAUTHORIZED, DAV_ERR_LOCK_SAVE_LOCK, "Anonymous lock removal is not allowed."); else if (serr) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to remove a lock.", resource->pool); } /* Log the unlocking as a 'high-level' action. */ apr_table_set(resource->info->r->subprocess_env, "SVN-ACTION", apr_psprintf(resource->info->r->pool, "unlock '%s'", svn_path_uri_encode(resource->info->repos_path, resource->info->r->pool))); return 0;}/*** Refresh all locks, found on the specified resource, which has a** locktoken in the provided list.**** If the lock is indirect, then the direct lock is referenced and** refreshed.**** Each lock that is updated is returned in the <locks> argument.** Note that the locks will be fully resolved.*/static dav_error *dav_svn_refresh_locks(dav_lockdb *lockdb, const dav_resource *resource, const dav_locktoken_list *ltl, time_t new_time, dav_lock **locks){ /* We're not looping over a list of locks, since we only support one lock per resource. */ dav_locktoken *token = ltl->locktoken; svn_error_t *serr; dav_error *derr; svn_lock_t *slock; dav_lock *dlock; svn_boolean_t readable = FALSE; /* If the resource's fs path is unreadable, we don't want to say anything about locks attached to it.*/ derr = check_readability(&readable, resource->info->r, resource->info->repos, resource->info->repos_path, resource->pool); if (derr) return derr; if (! readable) return dav_new_error(resource->pool, HTTP_FORBIDDEN, DAV_ERR_LOCK_SAVE_LOCK, "Path is not accessible."); /* Convert the path into an svn_lock_t. */ serr = svn_fs_get_lock(&slock, resource->info->repos->fs, resource->info->repos_path, resource->pool); if (serr) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Token doesn't point to a lock.", resource->pool); /* Sanity check: does the incoming token actually represent the current lock on the incoming resource? */ if ((! slock) || (strcmp(token->uuid_str, slock->token) != 0)) return dav_new_error(resource->pool, HTTP_UNAUTHORIZED, DAV_ERR_LOCK_SAVE_LOCK, "Lock refresh request doesn't match existing lock."); /* Now use the tweaked svn_lock_t to 'refresh' the existing lock. */ serr = svn_repos_fs_lock(&slock, resource->info->repos->repos, slock->path, slock->token, slock->comment, slock->is_dav_comment, (new_time == DAV_TIMEOUT_INFINITE) ? 0 : (apr_time_t)new_time * APR_USEC_PER_SEC, SVN_INVALID_REVNUM, TRUE, /* forcibly steal existing lock */ resource->pool); if (serr && serr->apr_err == SVN_ERR_FS_NO_USER) return dav_new_error(resource->pool, HTTP_UNAUTHORIZED, DAV_ERR_LOCK_SAVE_LOCK, "Anonymous lock refreshing is not allowed."); else if (serr) return dav_svn_convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "Failed to refresh existing lock.", resource->pool); /* Convert the refreshed lock into a dav_lock and return it. */ svn_lock_to_dav_lock(&dlock, slock, FALSE, resource->exists, resource->pool); *locks = dlock; return 0;}/* The main locking vtable, provided to mod_dav */const dav_hooks_locks dav_svn_hooks_locks = { dav_svn_get_supportedlock, dav_svn_parse_locktoken, dav_svn_format_locktoken, dav_svn_compare_locktoken, dav_svn_open_lockdb, dav_svn_close_lockdb, dav_svn_remove_locknull_state, dav_svn_create_lock, dav_svn_get_locks, dav_svn_find_lock, dav_svn_has_locks, dav_svn_append_locks, dav_svn_remove_lock, dav_svn_refresh_locks, NULL, NULL /* hook structure context */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -