📄 serve.c
字号:
svn_revnum_t rev; apr_time_t tm; const char *timestr; SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c", ×tr)); SVN_ERR(trivial_auth_request(conn, pool, b)); SVN_CMD_ERR(svn_time_from_cstring(&tm, timestr, pool)); SVN_CMD_ERR(svn_repos_dated_revision(&rev, b->repos, tm, pool)); SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, "r", rev)); return SVN_NO_ERROR;}static svn_error_t *change_rev_prop(svn_ra_svn_conn_t *conn, apr_pool_t *pool, apr_array_header_t *params, void *baton){ server_baton_t *b = baton; svn_revnum_t rev; const char *name; svn_string_t *value; SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "rc?s", &rev, &name, &value)); SVN_ERR(must_have_access(conn, pool, b, svn_authz_write, NULL, FALSE)); SVN_CMD_ERR(svn_repos_fs_change_rev_prop2(b->repos, rev, b->user, name, value, authz_check_access_cb_func(b), b, pool)); SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, "")); return SVN_NO_ERROR;}static svn_error_t *rev_proplist(svn_ra_svn_conn_t *conn, apr_pool_t *pool, apr_array_header_t *params, void *baton){ server_baton_t *b = baton; svn_revnum_t rev; apr_hash_t *props; SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "r", &rev)); SVN_ERR(trivial_auth_request(conn, pool, b)); SVN_CMD_ERR(svn_repos_fs_revision_proplist(&props, b->repos, rev, authz_check_access_cb_func(b), b, pool)); SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w((!", "success")); SVN_ERR(write_proplist(conn, pool, props)); SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!))")); return SVN_NO_ERROR;}static svn_error_t *rev_prop(svn_ra_svn_conn_t *conn, apr_pool_t *pool, apr_array_header_t *params, void *baton){ server_baton_t *b = baton; svn_revnum_t rev; const char *name; svn_string_t *value; SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "rc", &rev, &name)); SVN_ERR(trivial_auth_request(conn, pool, b)); SVN_CMD_ERR(svn_repos_fs_revision_prop(&value, b->repos, rev, name, authz_check_access_cb_func(b), b, pool)); SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, "(?s)", value)); return SVN_NO_ERROR;}static svn_error_t *commit_done(const svn_commit_info_t *commit_info, void *baton, apr_pool_t *pool){ commit_callback_baton_t *ccb = baton; *ccb->new_rev = commit_info->revision; *ccb->date = commit_info->date ? apr_pstrdup(ccb->pool, commit_info->date): NULL; *ccb->author = commit_info->author ? apr_pstrdup(ccb->pool, commit_info->author) : NULL; *ccb->post_commit_err = commit_info->post_commit_err ? apr_pstrdup(ccb->pool, commit_info->post_commit_err) : NULL; return SVN_NO_ERROR;}/* Add the LOCK_TOKENS (if any) to the filesystem access context, * checking path authorizations using the state in SB as we go. * LOCK_TOKENS is an array of svn_ra_svn_item_t structs. Return a * client error if LOCK_TOKENS is not a list of lists. If a lock * violates the authz configuration, return SVN_ERR_RA_NOT_AUTHORIZED * to the client. Use POOL for temporary allocations only. */static svn_error_t *add_lock_tokens(svn_ra_svn_conn_t *conn, apr_array_header_t *lock_tokens, server_baton_t *sb, apr_pool_t *pool){ int i; svn_fs_access_t *fs_access; SVN_ERR(svn_fs_get_access(&fs_access, sb->fs)); /* If there is no access context, nowhere to add the tokens. */ if (! fs_access) return SVN_NO_ERROR; for (i = 0; i < lock_tokens->nelts; ++i) { const char *token; svn_ra_svn_item_t *path_item, *token_item; svn_ra_svn_item_t *item = &APR_ARRAY_IDX(lock_tokens, i, svn_ra_svn_item_t); if (item->kind != SVN_RA_SVN_LIST) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, "Lock tokens aren't a list of lists"); path_item = &APR_ARRAY_IDX(item->u.list, 0, svn_ra_svn_item_t); if (path_item->kind != SVN_RA_SVN_STRING) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, "Lock path isn't a string"); token_item = &APR_ARRAY_IDX(item->u.list, 1, svn_ra_svn_item_t); if (token_item->kind != SVN_RA_SVN_STRING) return svn_error_create(SVN_ERR_RA_SVN_MALFORMED_DATA, NULL, "Lock token isn't a string"); if (! lookup_access(pool, sb, svn_authz_write, path_item->u.string->data, TRUE)) return svn_error_create(SVN_ERR_RA_NOT_AUTHORIZED, NULL, NULL); token = token_item->u.string->data; SVN_ERR(svn_fs_access_add_lock_token(fs_access, token)); } return SVN_NO_ERROR;}/* Unlock the paths with lock tokens in LOCK_TOKENS, ignoring any errors. LOCK_TOKENS contains svn_ra_svn_item_t elements, assumed to be lists. */static svn_error_t *unlock_paths(apr_array_header_t *lock_tokens, server_baton_t *sb, apr_pool_t *pool){ int i; apr_pool_t *iterpool; iterpool = svn_pool_create(pool); for (i = 0; i < lock_tokens->nelts; ++i) { svn_ra_svn_item_t *item, *path_item, *token_item; const char *path, *token, *full_path; svn_pool_clear(iterpool); item = &APR_ARRAY_IDX(lock_tokens, i, svn_ra_svn_item_t); path_item = &APR_ARRAY_IDX(item->u.list, 0, svn_ra_svn_item_t); token_item = &APR_ARRAY_IDX(item->u.list, 1, svn_ra_svn_item_t); path = path_item->u.string->data; token = token_item->u.string->data; full_path = svn_path_join(sb->fs_path->data, svn_path_canonicalize(path, iterpool), iterpool); /* The lock may have become defunct after the commit, so ignore such errors. ### If we ever write a logging facility for svnserve, this would be a good place to log an error before clearing it. */ svn_error_clear(svn_repos_fs_unlock(sb->repos, full_path, token, FALSE, pool)); } svn_pool_destroy(iterpool); return SVN_NO_ERROR;}static svn_error_t *commit(svn_ra_svn_conn_t *conn, apr_pool_t *pool, apr_array_header_t *params, void *baton){ server_baton_t *b = baton; const char *log_msg = NULL, *date = NULL, *author = NULL, *post_commit_err = NULL; apr_array_header_t *lock_tokens; svn_boolean_t keep_locks; const svn_delta_editor_t *editor; void *edit_baton; svn_boolean_t aborted; commit_callback_baton_t ccb; svn_revnum_t new_rev; if (params->nelts == 1) { /* Clients before 1.2 don't send lock-tokens and keep-locks fields. */ SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c", &log_msg)); lock_tokens = NULL; keep_locks = TRUE; } else SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "clb", &log_msg, &lock_tokens, &keep_locks)); /* The handling for locks is a little problematic, because the protocol won't let us send several auth requests once one has succeeded. So we request write access and a username before adding tokens (if we have any), and subsequently fail if a lock violates authz. */ SVN_ERR(must_have_access(conn, pool, b, svn_authz_write, NULL, (lock_tokens && lock_tokens->nelts) ? TRUE : FALSE)); /* Authorize the lock tokens and give them to the FS if we got any. */ if (lock_tokens && lock_tokens->nelts) SVN_CMD_ERR(add_lock_tokens(conn, lock_tokens, b, pool)); ccb.pool = pool; ccb.new_rev = &new_rev; ccb.date = &date; ccb.author = &author; ccb.post_commit_err = &post_commit_err; /* ### Note that svn_repos_get_commit_editor actually wants a decoded URL. */ SVN_CMD_ERR(svn_repos_get_commit_editor4 (&editor, &edit_baton, b->repos, NULL, svn_path_uri_decode(b->repos_url, pool), b->fs_path->data, b->user, log_msg, commit_done, &ccb, authz_commit_cb, baton, pool)); SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, "")); SVN_ERR(svn_ra_svn_drive_editor(conn, pool, editor, edit_baton, &aborted)); if (!aborted) { SVN_ERR(trivial_auth_request(conn, pool, b)); /* In tunnel mode, deltify before answering the client, because answering may cause the client to terminate the connection and thus kill the server. But otherwise, deltify after answering the client, to avoid user-visible delay. */ if (b->tunnel) SVN_ERR(svn_fs_deltify_revision(b->fs, new_rev, pool)); /* Unlock the paths. */ if (! keep_locks && lock_tokens && lock_tokens->nelts) SVN_ERR(unlock_paths(lock_tokens, b, pool)); SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "r(?c)(?c)(?c)", new_rev, date, author, post_commit_err)); if (! b->tunnel) SVN_ERR(svn_fs_deltify_revision(b->fs, new_rev, pool)); } return SVN_NO_ERROR;}static svn_error_t *get_file(svn_ra_svn_conn_t *conn, apr_pool_t *pool, apr_array_header_t *params, void *baton){ server_baton_t *b = baton; const char *path, *full_path, *hex_digest; svn_revnum_t rev; svn_fs_root_t *root; svn_stream_t *contents; apr_hash_t *props = NULL; svn_string_t write_str; char buf[4096]; apr_size_t len; svn_boolean_t want_props, want_contents; unsigned char digest[APR_MD5_DIGESTSIZE]; svn_error_t *err, *write_err; /* Parse arguments. */ SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c(?r)bb", &path, &rev, &want_props, &want_contents)); full_path = svn_path_join(b->fs_path->data, svn_path_canonicalize(path, pool), pool); /* Check authorizations */ SVN_ERR(must_have_access(conn, pool, b, svn_authz_read, full_path, FALSE)); if (!SVN_IS_VALID_REVNUM(rev)) SVN_CMD_ERR(svn_fs_youngest_rev(&rev, b->fs, pool)); /* Fetch the properties and a stream for the contents. */ SVN_CMD_ERR(svn_fs_revision_root(&root, b->fs, rev, pool)); SVN_CMD_ERR(svn_fs_file_md5_checksum(digest, root, full_path, pool)); hex_digest = svn_md5_digest_to_cstring_display(digest, pool); if (want_props) SVN_CMD_ERR(get_props(&props, root, full_path, pool)); if (want_contents) SVN_CMD_ERR(svn_fs_file_contents(&contents, root, full_path, pool)); /* Send successful command response with revision and props. */ SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "w((?c)r(!", "success", hex_digest, rev)); SVN_ERR(write_proplist(conn, pool, props)); SVN_ERR(svn_ra_svn_write_tuple(conn, pool, "!))")); /* Now send the file's contents. */ if (want_contents) { err = SVN_NO_ERROR; while (1) { len = sizeof(buf); err = svn_stream_read(contents, buf, &len); if (err) break; if (len > 0) { write_str.data = buf; write_str.len = len; SVN_ERR(svn_ra_svn_write_string(conn, pool, &write_str)); } if (len < sizeof(buf)) { err = svn_stream_close(contents); break; } } write_err = svn_ra_svn_write_cstring(conn, pool, ""); if (write_err) { svn_error_clear(err); return write_err; } SVN_CMD_ERR(err); SVN_ERR(svn_ra_svn_write_cmd_response(conn, pool, "")); } return SVN_NO_ERROR;}static svn_error_t *get_dir(svn_ra_svn_conn_t *conn, apr_pool_t *pool, apr_array_header_t *params, void *baton){ server_baton_t *b = baton; const char *path, *full_path, *file_path, *name, *cauthor, *cdate; svn_revnum_t rev; apr_hash_t *entries, *props = NULL, *file_props; apr_hash_index_t *hi; svn_fs_dirent_t *fsent; svn_dirent_t *entry; const void *key; void *val; svn_fs_root_t *root; apr_pool_t *subpool; svn_boolean_t want_props, want_contents; apr_uint64_t dirent_fields; apr_array_header_t *dirent_fields_list = NULL; svn_ra_svn_item_t *elt; int i; SVN_ERR(svn_ra_svn_parse_tuple(params, pool, "c(?r)bb?l", &path, &rev, &want_props, &want_contents, &dirent_fields_list)); if (! dirent_fields_list) { dirent_fields = SVN_DIRENT_ALL; } else { dirent_fields = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -