1251881Speter/* 2251881Speter * util.c : utility functions for the libsvn_client library 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter#include <apr_pools.h> 25251881Speter#include <apr_strings.h> 26251881Speter 27251881Speter#include "svn_hash.h" 28251881Speter#include "svn_pools.h" 29251881Speter#include "svn_error.h" 30251881Speter#include "svn_types.h" 31251881Speter#include "svn_opt.h" 32251881Speter#include "svn_props.h" 33251881Speter#include "svn_path.h" 34251881Speter#include "svn_wc.h" 35251881Speter#include "svn_client.h" 36251881Speter 37251881Speter#include "private/svn_client_private.h" 38251881Speter#include "private/svn_wc_private.h" 39251881Speter#include "private/svn_fspath.h" 40251881Speter 41251881Speter#include "client.h" 42251881Speter 43251881Speter#include "svn_private_config.h" 44251881Speter 45251881Spetersvn_client__pathrev_t * 46251881Spetersvn_client__pathrev_create(const char *repos_root_url, 47251881Speter const char *repos_uuid, 48251881Speter svn_revnum_t rev, 49251881Speter const char *url, 50251881Speter apr_pool_t *result_pool) 51251881Speter{ 52251881Speter svn_client__pathrev_t *loc = apr_palloc(result_pool, sizeof(*loc)); 53251881Speter 54251881Speter SVN_ERR_ASSERT_NO_RETURN(svn_path_is_url(repos_root_url)); 55251881Speter SVN_ERR_ASSERT_NO_RETURN(svn_path_is_url(url)); 56251881Speter 57251881Speter loc->repos_root_url = apr_pstrdup(result_pool, repos_root_url); 58251881Speter loc->repos_uuid = apr_pstrdup(result_pool, repos_uuid); 59251881Speter loc->rev = rev; 60251881Speter loc->url = apr_pstrdup(result_pool, url); 61251881Speter return loc; 62251881Speter} 63251881Speter 64251881Spetersvn_client__pathrev_t * 65251881Spetersvn_client__pathrev_create_with_relpath(const char *repos_root_url, 66251881Speter const char *repos_uuid, 67251881Speter svn_revnum_t rev, 68251881Speter const char *relpath, 69251881Speter apr_pool_t *result_pool) 70251881Speter{ 71251881Speter SVN_ERR_ASSERT_NO_RETURN(svn_relpath_is_canonical(relpath)); 72251881Speter 73251881Speter return svn_client__pathrev_create( 74251881Speter repos_root_url, repos_uuid, rev, 75251881Speter svn_path_url_add_component2(repos_root_url, relpath, result_pool), 76251881Speter result_pool); 77251881Speter} 78251881Speter 79251881Spetersvn_error_t * 80251881Spetersvn_client__pathrev_create_with_session(svn_client__pathrev_t **pathrev_p, 81251881Speter svn_ra_session_t *ra_session, 82251881Speter svn_revnum_t rev, 83251881Speter const char *url, 84251881Speter apr_pool_t *result_pool) 85251881Speter{ 86251881Speter svn_client__pathrev_t *pathrev = apr_palloc(result_pool, sizeof(*pathrev)); 87251881Speter 88251881Speter SVN_ERR_ASSERT(svn_path_is_url(url)); 89251881Speter 90251881Speter SVN_ERR(svn_ra_get_repos_root2(ra_session, &pathrev->repos_root_url, 91251881Speter result_pool)); 92251881Speter SVN_ERR(svn_ra_get_uuid2(ra_session, &pathrev->repos_uuid, result_pool)); 93251881Speter pathrev->rev = rev; 94251881Speter pathrev->url = apr_pstrdup(result_pool, url); 95251881Speter *pathrev_p = pathrev; 96251881Speter return SVN_NO_ERROR; 97251881Speter} 98251881Speter 99251881Spetersvn_client__pathrev_t * 100251881Spetersvn_client__pathrev_dup(const svn_client__pathrev_t *pathrev, 101251881Speter apr_pool_t *result_pool) 102251881Speter{ 103251881Speter return svn_client__pathrev_create( 104251881Speter pathrev->repos_root_url, pathrev->repos_uuid, 105251881Speter pathrev->rev, pathrev->url, result_pool); 106251881Speter} 107251881Speter 108251881Spetersvn_client__pathrev_t * 109251881Spetersvn_client__pathrev_join_relpath(const svn_client__pathrev_t *pathrev, 110251881Speter const char *relpath, 111251881Speter apr_pool_t *result_pool) 112251881Speter{ 113251881Speter return svn_client__pathrev_create( 114251881Speter pathrev->repos_root_url, pathrev->repos_uuid, pathrev->rev, 115251881Speter svn_path_url_add_component2(pathrev->url, relpath, result_pool), 116251881Speter result_pool); 117251881Speter} 118251881Speter 119251881Speterconst char * 120251881Spetersvn_client__pathrev_relpath(const svn_client__pathrev_t *pathrev, 121251881Speter apr_pool_t *result_pool) 122251881Speter{ 123251881Speter return svn_uri_skip_ancestor(pathrev->repos_root_url, pathrev->url, 124251881Speter result_pool); 125251881Speter} 126251881Speter 127251881Speterconst char * 128251881Spetersvn_client__pathrev_fspath(const svn_client__pathrev_t *pathrev, 129251881Speter apr_pool_t *result_pool) 130251881Speter{ 131251881Speter return svn_fspath__canonicalize(svn_uri_skip_ancestor( 132251881Speter pathrev->repos_root_url, pathrev->url, 133251881Speter result_pool), 134251881Speter result_pool); 135251881Speter} 136251881Speter 137251881Speter 138251881Spetersvn_client_commit_item3_t * 139251881Spetersvn_client_commit_item3_create(apr_pool_t *pool) 140251881Speter{ 141251881Speter return apr_pcalloc(pool, sizeof(svn_client_commit_item3_t)); 142251881Speter} 143251881Speter 144251881Spetersvn_client_commit_item3_t * 145251881Spetersvn_client_commit_item3_dup(const svn_client_commit_item3_t *item, 146251881Speter apr_pool_t *pool) 147251881Speter{ 148251881Speter svn_client_commit_item3_t *new_item = apr_palloc(pool, sizeof(*new_item)); 149251881Speter 150251881Speter *new_item = *item; 151251881Speter 152251881Speter if (new_item->path) 153251881Speter new_item->path = apr_pstrdup(pool, new_item->path); 154251881Speter 155251881Speter if (new_item->url) 156251881Speter new_item->url = apr_pstrdup(pool, new_item->url); 157251881Speter 158251881Speter if (new_item->copyfrom_url) 159251881Speter new_item->copyfrom_url = apr_pstrdup(pool, new_item->copyfrom_url); 160251881Speter 161251881Speter if (new_item->incoming_prop_changes) 162251881Speter new_item->incoming_prop_changes = 163251881Speter svn_prop_array_dup(new_item->incoming_prop_changes, pool); 164251881Speter 165251881Speter if (new_item->outgoing_prop_changes) 166251881Speter new_item->outgoing_prop_changes = 167251881Speter svn_prop_array_dup(new_item->outgoing_prop_changes, pool); 168251881Speter 169251881Speter return new_item; 170251881Speter} 171251881Speter 172251881Spetersvn_error_t * 173251881Spetersvn_client__wc_node_get_base(svn_client__pathrev_t **base_p, 174251881Speter const char *wc_abspath, 175251881Speter svn_wc_context_t *wc_ctx, 176251881Speter apr_pool_t *result_pool, 177251881Speter apr_pool_t *scratch_pool) 178251881Speter{ 179251881Speter const char *relpath; 180251881Speter 181251881Speter *base_p = apr_palloc(result_pool, sizeof(**base_p)); 182251881Speter 183251881Speter SVN_ERR(svn_wc__node_get_base(NULL, 184251881Speter &(*base_p)->rev, 185251881Speter &relpath, 186251881Speter &(*base_p)->repos_root_url, 187251881Speter &(*base_p)->repos_uuid, 188251881Speter NULL, 189251881Speter wc_ctx, wc_abspath, 190251881Speter TRUE /* ignore_enoent */, 191251881Speter TRUE /* show_hidden */, 192251881Speter result_pool, scratch_pool)); 193251881Speter if ((*base_p)->repos_root_url && relpath) 194251881Speter { 195251881Speter (*base_p)->url = svn_path_url_add_component2( 196251881Speter (*base_p)->repos_root_url, relpath, result_pool); 197251881Speter } 198251881Speter else 199251881Speter { 200251881Speter *base_p = NULL; 201251881Speter } 202251881Speter return SVN_NO_ERROR; 203251881Speter} 204251881Speter 205251881Spetersvn_error_t * 206251881Spetersvn_client__wc_node_get_origin(svn_client__pathrev_t **origin_p, 207251881Speter const char *wc_abspath, 208251881Speter svn_client_ctx_t *ctx, 209251881Speter apr_pool_t *result_pool, 210251881Speter apr_pool_t *scratch_pool) 211251881Speter{ 212251881Speter const char *relpath; 213251881Speter 214251881Speter *origin_p = apr_palloc(result_pool, sizeof(**origin_p)); 215251881Speter 216251881Speter SVN_ERR(svn_wc__node_get_origin(NULL /* is_copy */, 217251881Speter &(*origin_p)->rev, 218251881Speter &relpath, 219251881Speter &(*origin_p)->repos_root_url, 220251881Speter &(*origin_p)->repos_uuid, 221251881Speter NULL, ctx->wc_ctx, wc_abspath, 222251881Speter FALSE /* scan_deleted */, 223251881Speter result_pool, scratch_pool)); 224251881Speter if ((*origin_p)->repos_root_url && relpath) 225251881Speter { 226251881Speter (*origin_p)->url = svn_path_url_add_component2( 227251881Speter (*origin_p)->repos_root_url, relpath, result_pool); 228251881Speter } 229251881Speter else 230251881Speter { 231251881Speter *origin_p = NULL; 232251881Speter } 233251881Speter return SVN_NO_ERROR; 234251881Speter} 235251881Speter 236251881Spetersvn_error_t * 237251881Spetersvn_client_get_repos_root(const char **repos_root, 238251881Speter const char **repos_uuid, 239251881Speter const char *abspath_or_url, 240251881Speter svn_client_ctx_t *ctx, 241251881Speter apr_pool_t *result_pool, 242251881Speter apr_pool_t *scratch_pool) 243251881Speter{ 244251881Speter svn_ra_session_t *ra_session; 245251881Speter 246251881Speter /* If PATH_OR_URL is a local path we can fetch the repos root locally. */ 247251881Speter if (!svn_path_is_url(abspath_or_url)) 248251881Speter { 249251881Speter svn_error_t *err; 250251881Speter err = svn_wc__node_get_repos_info(NULL, NULL, repos_root, repos_uuid, 251251881Speter ctx->wc_ctx, abspath_or_url, 252251881Speter result_pool, scratch_pool); 253251881Speter 254251881Speter if (err) 255251881Speter { 256251881Speter if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND 257251881Speter && err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY) 258251881Speter return svn_error_trace(err); 259251881Speter 260251881Speter svn_error_clear(err); 261251881Speter if (repos_root) 262251881Speter *repos_root = NULL; 263251881Speter if (repos_uuid) 264251881Speter *repos_uuid = NULL; 265251881Speter } 266251881Speter return SVN_NO_ERROR; 267251881Speter } 268251881Speter 269251881Speter /* If PATH_OR_URL was a URL, we use the RA layer to look it up. */ 270251881Speter SVN_ERR(svn_client_open_ra_session2(&ra_session, abspath_or_url, NULL, 271251881Speter ctx, scratch_pool, scratch_pool)); 272251881Speter 273251881Speter if (repos_root) 274251881Speter SVN_ERR(svn_ra_get_repos_root2(ra_session, repos_root, result_pool)); 275251881Speter if (repos_uuid) 276251881Speter SVN_ERR(svn_ra_get_uuid2(ra_session, repos_uuid, result_pool)); 277251881Speter 278251881Speter return SVN_NO_ERROR; 279251881Speter} 280251881Speter 281251881Speterconst svn_opt_revision_t * 282251881Spetersvn_cl__rev_default_to_head_or_base(const svn_opt_revision_t *revision, 283251881Speter const char *path_or_url) 284251881Speter{ 285251881Speter static svn_opt_revision_t head_rev = { svn_opt_revision_head, { 0 } }; 286251881Speter static svn_opt_revision_t base_rev = { svn_opt_revision_base, { 0 } }; 287251881Speter 288251881Speter if (revision->kind == svn_opt_revision_unspecified) 289251881Speter return svn_path_is_url(path_or_url) ? &head_rev : &base_rev; 290251881Speter return revision; 291251881Speter} 292251881Speter 293251881Speterconst svn_opt_revision_t * 294251881Spetersvn_cl__rev_default_to_head_or_working(const svn_opt_revision_t *revision, 295251881Speter const char *path_or_url) 296251881Speter{ 297251881Speter static svn_opt_revision_t head_rev = { svn_opt_revision_head, { 0 } }; 298251881Speter static svn_opt_revision_t work_rev = { svn_opt_revision_working, { 0 } }; 299251881Speter 300251881Speter if (revision->kind == svn_opt_revision_unspecified) 301251881Speter return svn_path_is_url(path_or_url) ? &head_rev : &work_rev; 302251881Speter return revision; 303251881Speter} 304251881Speter 305251881Speterconst svn_opt_revision_t * 306251881Spetersvn_cl__rev_default_to_peg(const svn_opt_revision_t *revision, 307251881Speter const svn_opt_revision_t *peg_revision) 308251881Speter{ 309251881Speter if (revision->kind == svn_opt_revision_unspecified) 310251881Speter return peg_revision; 311251881Speter return revision; 312251881Speter} 313251881Speter 314251881Spetersvn_error_t * 315251881Spetersvn_client__assert_homogeneous_target_type(const apr_array_header_t *targets) 316251881Speter{ 317251881Speter svn_boolean_t wc_present = FALSE, url_present = FALSE; 318251881Speter int i; 319251881Speter 320251881Speter for (i = 0; i < targets->nelts; ++i) 321251881Speter { 322251881Speter const char *target = APR_ARRAY_IDX(targets, i, const char *); 323251881Speter if (! svn_path_is_url(target)) 324251881Speter wc_present = TRUE; 325251881Speter else 326251881Speter url_present = TRUE; 327251881Speter if (url_present && wc_present) 328251881Speter return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL, 329251881Speter _("Cannot mix repository and working copy " 330251881Speter "targets")); 331251881Speter } 332251881Speter 333251881Speter return SVN_NO_ERROR; 334251881Speter} 335251881Speter 336251881Speterstruct shim_callbacks_baton 337251881Speter{ 338251881Speter svn_wc_context_t *wc_ctx; 339251881Speter apr_hash_t *relpath_map; 340251881Speter}; 341251881Speter 342251881Speterstatic svn_error_t * 343251881Speterfetch_props_func(apr_hash_t **props, 344251881Speter void *baton, 345251881Speter const char *path, 346251881Speter svn_revnum_t base_revision, 347251881Speter apr_pool_t *result_pool, 348251881Speter apr_pool_t *scratch_pool) 349251881Speter{ 350251881Speter struct shim_callbacks_baton *scb = baton; 351251881Speter const char *local_abspath; 352251881Speter 353251881Speter local_abspath = svn_hash_gets(scb->relpath_map, path); 354251881Speter if (!local_abspath) 355251881Speter { 356251881Speter *props = apr_hash_make(result_pool); 357251881Speter return SVN_NO_ERROR; 358251881Speter } 359251881Speter 360251881Speter /* Reads the pristine properties of WORKING, not those of BASE */ 361251881Speter SVN_ERR(svn_wc_get_pristine_props(props, scb->wc_ctx, local_abspath, 362251881Speter result_pool, scratch_pool)); 363251881Speter 364251881Speter if (!*props) 365251881Speter *props = apr_hash_make(result_pool); 366251881Speter 367251881Speter return SVN_NO_ERROR; 368251881Speter} 369251881Speter 370251881Speterstatic svn_error_t * 371251881Speterfetch_kind_func(svn_node_kind_t *kind, 372251881Speter void *baton, 373251881Speter const char *path, 374251881Speter svn_revnum_t base_revision, 375251881Speter apr_pool_t *scratch_pool) 376251881Speter{ 377251881Speter struct shim_callbacks_baton *scb = baton; 378251881Speter const char *local_abspath; 379251881Speter 380251881Speter local_abspath = svn_hash_gets(scb->relpath_map, path); 381251881Speter if (!local_abspath) 382251881Speter { 383251881Speter *kind = svn_node_unknown; 384251881Speter return SVN_NO_ERROR; 385251881Speter } 386251881Speter /* Reads the WORKING kind. Not the BASE kind */ 387251881Speter SVN_ERR(svn_wc_read_kind2(kind, scb->wc_ctx, local_abspath, 388251881Speter TRUE, FALSE, scratch_pool)); 389251881Speter 390251881Speter return SVN_NO_ERROR; 391251881Speter} 392251881Speter 393251881Speterstatic svn_error_t * 394251881Speterfetch_base_func(const char **filename, 395251881Speter void *baton, 396251881Speter const char *path, 397251881Speter svn_revnum_t base_revision, 398251881Speter apr_pool_t *result_pool, 399251881Speter apr_pool_t *scratch_pool) 400251881Speter{ 401251881Speter struct shim_callbacks_baton *scb = baton; 402251881Speter const char *local_abspath; 403251881Speter svn_stream_t *pristine_stream; 404251881Speter svn_stream_t *temp_stream; 405251881Speter svn_error_t *err; 406251881Speter 407251881Speter local_abspath = svn_hash_gets(scb->relpath_map, path); 408251881Speter if (!local_abspath) 409251881Speter { 410251881Speter *filename = NULL; 411251881Speter return SVN_NO_ERROR; 412251881Speter } 413251881Speter 414251881Speter /* Reads the pristine of WORKING, not of BASE */ 415251881Speter err = svn_wc_get_pristine_contents2(&pristine_stream, scb->wc_ctx, 416251881Speter local_abspath, scratch_pool, 417251881Speter scratch_pool); 418251881Speter if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND) 419251881Speter { 420251881Speter svn_error_clear(err); 421251881Speter *filename = NULL; 422251881Speter return SVN_NO_ERROR; 423251881Speter } 424251881Speter else if (err) 425251881Speter return svn_error_trace(err); 426251881Speter 427251881Speter SVN_ERR(svn_stream_open_unique(&temp_stream, filename, NULL, 428251881Speter svn_io_file_del_on_pool_cleanup, 429251881Speter result_pool, scratch_pool)); 430251881Speter SVN_ERR(svn_stream_copy3(pristine_stream, temp_stream, NULL, NULL, 431251881Speter scratch_pool)); 432251881Speter 433251881Speter return SVN_NO_ERROR; 434251881Speter} 435251881Speter 436251881Spetersvn_delta_shim_callbacks_t * 437251881Spetersvn_client__get_shim_callbacks(svn_wc_context_t *wc_ctx, 438251881Speter apr_hash_t *relpath_map, 439251881Speter apr_pool_t *result_pool) 440251881Speter{ 441251881Speter svn_delta_shim_callbacks_t *callbacks = 442251881Speter svn_delta_shim_callbacks_default(result_pool); 443251881Speter struct shim_callbacks_baton *scb = apr_pcalloc(result_pool, sizeof(*scb)); 444251881Speter 445251881Speter scb->wc_ctx = wc_ctx; 446251881Speter if (relpath_map) 447251881Speter scb->relpath_map = relpath_map; 448251881Speter else 449251881Speter scb->relpath_map = apr_hash_make(result_pool); 450251881Speter 451251881Speter callbacks->fetch_props_func = fetch_props_func; 452251881Speter callbacks->fetch_kind_func = fetch_kind_func; 453251881Speter callbacks->fetch_base_func = fetch_base_func; 454251881Speter callbacks->fetch_baton = scb; 455251881Speter 456251881Speter return callbacks; 457251881Speter} 458