1251881Speter/* 2251881Speter * copy_foreign.c: copy from other repository support. 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/* ==================================================================== */ 25251881Speter 26251881Speter/*** Includes. ***/ 27251881Speter 28251881Speter#include <string.h> 29251881Speter#include "svn_hash.h" 30251881Speter#include "svn_client.h" 31251881Speter#include "svn_delta.h" 32251881Speter#include "svn_dirent_uri.h" 33251881Speter#include "svn_error.h" 34251881Speter#include "svn_error_codes.h" 35251881Speter#include "svn_path.h" 36251881Speter#include "svn_pools.h" 37251881Speter#include "svn_props.h" 38251881Speter#include "svn_ra.h" 39251881Speter#include "svn_wc.h" 40251881Speter 41251881Speter#include <apr_md5.h> 42251881Speter 43251881Speter#include "client.h" 44251881Speter#include "private/svn_subr_private.h" 45251881Speter#include "private/svn_wc_private.h" 46251881Speter#include "svn_private_config.h" 47251881Speter 48251881Speterstruct edit_baton_t 49251881Speter{ 50251881Speter apr_pool_t *pool; 51251881Speter const char *anchor_abspath; 52251881Speter 53251881Speter svn_wc_context_t *wc_ctx; 54251881Speter svn_wc_notify_func2_t notify_func; 55251881Speter void *notify_baton; 56251881Speter}; 57251881Speter 58251881Speterstruct dir_baton_t 59251881Speter{ 60251881Speter apr_pool_t *pool; 61251881Speter 62251881Speter struct dir_baton_t *pb; 63251881Speter struct edit_baton_t *eb; 64251881Speter 65251881Speter const char *local_abspath; 66251881Speter 67251881Speter svn_boolean_t created; 68251881Speter apr_hash_t *properties; 69251881Speter 70251881Speter int users; 71251881Speter}; 72251881Speter 73251881Speter/* svn_delta_editor_t function */ 74251881Speterstatic svn_error_t * 75251881Speteredit_open(void *edit_baton, 76251881Speter svn_revnum_t base_revision, 77251881Speter apr_pool_t *result_pool, 78251881Speter void **root_baton) 79251881Speter{ 80251881Speter struct edit_baton_t *eb = edit_baton; 81251881Speter apr_pool_t *dir_pool = svn_pool_create(eb->pool); 82251881Speter struct dir_baton_t *db = apr_pcalloc(dir_pool, sizeof(*db)); 83251881Speter 84251881Speter db->pool = dir_pool; 85251881Speter db->eb = eb; 86251881Speter db->users = 1; 87251881Speter db->local_abspath = eb->anchor_abspath; 88251881Speter 89251881Speter SVN_ERR(svn_io_make_dir_recursively(eb->anchor_abspath, dir_pool)); 90251881Speter 91251881Speter *root_baton = db; 92251881Speter 93251881Speter return SVN_NO_ERROR; 94251881Speter} 95251881Speter 96251881Speter/* svn_delta_editor_t function */ 97251881Speterstatic svn_error_t * 98251881Speteredit_close(void *edit_baton, 99251881Speter apr_pool_t *scratch_pool) 100251881Speter{ 101251881Speter return SVN_NO_ERROR; 102251881Speter} 103251881Speter 104251881Speterstatic svn_error_t * 105251881Speterdir_add(const char *path, 106251881Speter void *parent_baton, 107251881Speter const char *copyfrom_path, 108251881Speter svn_revnum_t copyfrom_revision, 109251881Speter apr_pool_t *result_pool, 110251881Speter void **child_baton) 111251881Speter{ 112251881Speter struct dir_baton_t *pb = parent_baton; 113251881Speter struct edit_baton_t *eb = pb->eb; 114251881Speter apr_pool_t *dir_pool = svn_pool_create(pb->pool); 115251881Speter struct dir_baton_t *db = apr_pcalloc(dir_pool, sizeof(*db)); 116251881Speter svn_boolean_t under_root; 117251881Speter 118251881Speter pb->users++; 119251881Speter 120251881Speter db->pb = pb; 121251881Speter db->eb = pb->eb; 122251881Speter db->pool = dir_pool; 123251881Speter db->users = 1; 124251881Speter 125251881Speter SVN_ERR(svn_dirent_is_under_root(&under_root, &db->local_abspath, 126251881Speter eb->anchor_abspath, path, db->pool)); 127251881Speter if (! under_root) 128251881Speter { 129251881Speter return svn_error_createf( 130251881Speter SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL, 131251881Speter _("Path '%s' is not in the working copy"), 132251881Speter svn_dirent_local_style(path, db->pool)); 133251881Speter } 134251881Speter 135251881Speter SVN_ERR(svn_io_make_dir_recursively(db->local_abspath, db->pool)); 136251881Speter 137251881Speter *child_baton = db; 138251881Speter return SVN_NO_ERROR; 139251881Speter} 140251881Speter 141251881Speterstatic svn_error_t * 142251881Speterdir_change_prop(void *dir_baton, 143251881Speter const char *name, 144251881Speter const svn_string_t *value, 145251881Speter apr_pool_t *scratch_pool) 146251881Speter{ 147251881Speter struct dir_baton_t *db = dir_baton; 148251881Speter struct edit_baton_t *eb = db->eb; 149251881Speter svn_prop_kind_t prop_kind; 150251881Speter 151251881Speter prop_kind = svn_property_kind2(name); 152251881Speter 153251881Speter if (prop_kind != svn_prop_regular_kind 154251881Speter || ! strcmp(name, SVN_PROP_MERGEINFO)) 155251881Speter { 156251881Speter /* We can't handle DAV, ENTRY and merge specific props here */ 157251881Speter return SVN_NO_ERROR; 158251881Speter } 159251881Speter 160251881Speter if (! db->created) 161251881Speter { 162251881Speter /* We can still store them in the hash for immediate addition 163299742Sdim with the svn_wc_add_from_disk3() call */ 164251881Speter if (! db->properties) 165251881Speter db->properties = apr_hash_make(db->pool); 166251881Speter 167251881Speter if (value != NULL) 168251881Speter svn_hash_sets(db->properties, apr_pstrdup(db->pool, name), 169251881Speter svn_string_dup(value, db->pool)); 170251881Speter } 171251881Speter else 172251881Speter { 173251881Speter /* We have already notified for this directory, so don't do that again */ 174251881Speter SVN_ERR(svn_wc_prop_set4(eb->wc_ctx, db->local_abspath, name, value, 175251881Speter svn_depth_empty, FALSE, NULL, 176299742Sdim NULL, NULL, /* Cancellation */ 177251881Speter NULL, NULL, /* Notification */ 178251881Speter scratch_pool)); 179251881Speter } 180251881Speter 181251881Speter return SVN_NO_ERROR; 182251881Speter} 183251881Speter 184251881Speter/* Releases the directory baton if there are no more users */ 185251881Speterstatic svn_error_t * 186251881Spetermaybe_done(struct dir_baton_t *db) 187251881Speter{ 188251881Speter db->users--; 189251881Speter 190251881Speter if (db->users == 0) 191251881Speter { 192251881Speter struct dir_baton_t *pb = db->pb; 193251881Speter 194251881Speter svn_pool_clear(db->pool); 195251881Speter 196251881Speter if (pb) 197251881Speter SVN_ERR(maybe_done(pb)); 198251881Speter } 199251881Speter 200251881Speter return SVN_NO_ERROR; 201251881Speter} 202251881Speter 203251881Speterstatic svn_error_t * 204251881Speterensure_added(struct dir_baton_t *db, 205251881Speter apr_pool_t *scratch_pool) 206251881Speter{ 207251881Speter if (db->created) 208251881Speter return SVN_NO_ERROR; 209251881Speter 210251881Speter if (db->pb) 211251881Speter SVN_ERR(ensure_added(db->pb, scratch_pool)); 212251881Speter 213251881Speter db->created = TRUE; 214251881Speter 215251881Speter /* Add the directory with all the already collected properties */ 216299742Sdim SVN_ERR(svn_wc_add_from_disk3(db->eb->wc_ctx, 217251881Speter db->local_abspath, 218251881Speter db->properties, 219299742Sdim TRUE /* skip checks */, 220251881Speter db->eb->notify_func, 221251881Speter db->eb->notify_baton, 222251881Speter scratch_pool)); 223251881Speter 224251881Speter return SVN_NO_ERROR; 225251881Speter} 226251881Speter 227251881Speterstatic svn_error_t * 228251881Speterdir_close(void *dir_baton, 229251881Speter apr_pool_t *scratch_pool) 230251881Speter{ 231251881Speter struct dir_baton_t *db = dir_baton; 232251881Speter /*struct edit_baton_t *eb = db->eb;*/ 233251881Speter 234251881Speter SVN_ERR(ensure_added(db, scratch_pool)); 235251881Speter 236251881Speter SVN_ERR(maybe_done(db)); 237251881Speter 238251881Speter return SVN_NO_ERROR; 239251881Speter} 240251881Speter 241251881Speterstruct file_baton_t 242251881Speter{ 243251881Speter apr_pool_t *pool; 244251881Speter 245251881Speter struct dir_baton_t *pb; 246251881Speter struct edit_baton_t *eb; 247251881Speter 248251881Speter const char *local_abspath; 249251881Speter apr_hash_t *properties; 250251881Speter 251251881Speter svn_boolean_t writing; 252251881Speter unsigned char digest[APR_MD5_DIGESTSIZE]; 253251881Speter 254251881Speter const char *tmp_path; 255251881Speter}; 256251881Speter 257251881Speterstatic svn_error_t * 258251881Speterfile_add(const char *path, 259251881Speter void *parent_baton, 260251881Speter const char *copyfrom_path, 261251881Speter svn_revnum_t copyfrom_revision, 262251881Speter apr_pool_t *result_pool, 263251881Speter void **file_baton) 264251881Speter{ 265251881Speter struct dir_baton_t *pb = parent_baton; 266251881Speter struct edit_baton_t *eb = pb->eb; 267251881Speter apr_pool_t *file_pool = svn_pool_create(pb->pool); 268251881Speter struct file_baton_t *fb = apr_pcalloc(file_pool, sizeof(*fb)); 269251881Speter svn_boolean_t under_root; 270251881Speter 271251881Speter pb->users++; 272251881Speter 273251881Speter fb->pool = file_pool; 274251881Speter fb->eb = eb; 275251881Speter fb->pb = pb; 276251881Speter 277251881Speter SVN_ERR(svn_dirent_is_under_root(&under_root, &fb->local_abspath, 278251881Speter eb->anchor_abspath, path, fb->pool)); 279251881Speter if (! under_root) 280251881Speter { 281251881Speter return svn_error_createf( 282251881Speter SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL, 283251881Speter _("Path '%s' is not in the working copy"), 284251881Speter svn_dirent_local_style(path, fb->pool)); 285251881Speter } 286251881Speter 287251881Speter *file_baton = fb; 288251881Speter return SVN_NO_ERROR; 289251881Speter} 290251881Speter 291251881Speterstatic svn_error_t * 292251881Speterfile_change_prop(void *file_baton, 293251881Speter const char *name, 294251881Speter const svn_string_t *value, 295251881Speter apr_pool_t *scratch_pool) 296251881Speter{ 297251881Speter struct file_baton_t *fb = file_baton; 298251881Speter svn_prop_kind_t prop_kind; 299251881Speter 300251881Speter prop_kind = svn_property_kind2(name); 301251881Speter 302251881Speter if (prop_kind != svn_prop_regular_kind 303251881Speter || ! strcmp(name, SVN_PROP_MERGEINFO)) 304251881Speter { 305251881Speter /* We can't handle DAV, ENTRY and merge specific props here */ 306251881Speter return SVN_NO_ERROR; 307251881Speter } 308251881Speter 309251881Speter /* We store all properties in the hash for immediate addition 310299742Sdim with the svn_wc_add_from_disk3() call */ 311251881Speter if (! fb->properties) 312251881Speter fb->properties = apr_hash_make(fb->pool); 313251881Speter 314251881Speter if (value != NULL) 315251881Speter svn_hash_sets(fb->properties, apr_pstrdup(fb->pool, name), 316251881Speter svn_string_dup(value, fb->pool)); 317251881Speter 318251881Speter return SVN_NO_ERROR; 319251881Speter} 320251881Speter 321251881Speterstatic svn_error_t * 322251881Speterfile_textdelta(void *file_baton, 323251881Speter const char *base_checksum, 324251881Speter apr_pool_t *result_pool, 325251881Speter svn_txdelta_window_handler_t *handler, 326251881Speter void **handler_baton) 327251881Speter{ 328251881Speter struct file_baton_t *fb = file_baton; 329251881Speter svn_stream_t *target; 330251881Speter 331251881Speter SVN_ERR_ASSERT(! fb->writing); 332251881Speter 333251881Speter SVN_ERR(svn_stream_open_writable(&target, fb->local_abspath, fb->pool, 334251881Speter fb->pool)); 335251881Speter 336251881Speter fb->writing = TRUE; 337251881Speter svn_txdelta_apply(svn_stream_empty(fb->pool) /* source */, 338251881Speter target, 339251881Speter fb->digest, 340251881Speter fb->local_abspath, 341251881Speter fb->pool, 342251881Speter /* Provide the handler directly */ 343251881Speter handler, handler_baton); 344251881Speter 345251881Speter return SVN_NO_ERROR; 346251881Speter} 347251881Speter 348251881Speterstatic svn_error_t * 349251881Speterfile_close(void *file_baton, 350251881Speter const char *text_checksum, 351251881Speter apr_pool_t *scratch_pool) 352251881Speter{ 353251881Speter struct file_baton_t *fb = file_baton; 354251881Speter struct edit_baton_t *eb = fb->eb; 355251881Speter struct dir_baton_t *pb = fb->pb; 356251881Speter 357251881Speter SVN_ERR(ensure_added(pb, fb->pool)); 358251881Speter 359251881Speter if (text_checksum) 360251881Speter { 361251881Speter svn_checksum_t *expected_checksum; 362251881Speter svn_checksum_t *actual_checksum; 363251881Speter 364251881Speter SVN_ERR(svn_checksum_parse_hex(&expected_checksum, svn_checksum_md5, 365251881Speter text_checksum, fb->pool)); 366251881Speter actual_checksum = svn_checksum__from_digest_md5(fb->digest, fb->pool); 367251881Speter 368251881Speter if (! svn_checksum_match(expected_checksum, actual_checksum)) 369251881Speter return svn_error_trace( 370251881Speter svn_checksum_mismatch_err(expected_checksum, 371251881Speter actual_checksum, 372251881Speter fb->pool, 373251881Speter _("Checksum mismatch for '%s'"), 374251881Speter svn_dirent_local_style( 375251881Speter fb->local_abspath, 376251881Speter fb->pool))); 377251881Speter } 378251881Speter 379299742Sdim SVN_ERR(svn_wc_add_from_disk3(eb->wc_ctx, fb->local_abspath, fb->properties, 380299742Sdim TRUE /* skip checks */, 381251881Speter eb->notify_func, eb->notify_baton, 382251881Speter fb->pool)); 383251881Speter 384251881Speter svn_pool_destroy(fb->pool); 385251881Speter SVN_ERR(maybe_done(pb)); 386251881Speter 387251881Speter return SVN_NO_ERROR; 388251881Speter} 389251881Speter 390251881Speterstatic svn_error_t * 391251881Spetercopy_foreign_dir(svn_ra_session_t *ra_session, 392251881Speter svn_client__pathrev_t *location, 393251881Speter svn_wc_context_t *wc_ctx, 394251881Speter const char *dst_abspath, 395251881Speter svn_depth_t depth, 396251881Speter svn_wc_notify_func2_t notify_func, 397251881Speter void *notify_baton, 398251881Speter svn_cancel_func_t cancel_func, 399251881Speter void *cancel_baton, 400251881Speter apr_pool_t *scratch_pool) 401251881Speter{ 402251881Speter struct edit_baton_t eb; 403251881Speter svn_delta_editor_t *editor = svn_delta_default_editor(scratch_pool); 404251881Speter const svn_delta_editor_t *wrapped_editor; 405251881Speter void *wrapped_baton; 406251881Speter const svn_ra_reporter3_t *reporter; 407251881Speter void *reporter_baton; 408251881Speter 409251881Speter eb.pool = scratch_pool; 410251881Speter eb.anchor_abspath = dst_abspath; 411251881Speter 412251881Speter eb.wc_ctx = wc_ctx; 413251881Speter eb.notify_func = notify_func; 414251881Speter eb.notify_baton = notify_baton; 415251881Speter 416251881Speter editor->open_root = edit_open; 417251881Speter editor->close_edit = edit_close; 418251881Speter 419251881Speter editor->add_directory = dir_add; 420251881Speter editor->change_dir_prop = dir_change_prop; 421251881Speter editor->close_directory = dir_close; 422251881Speter 423251881Speter editor->add_file = file_add; 424251881Speter editor->change_file_prop = file_change_prop; 425251881Speter editor->apply_textdelta = file_textdelta; 426251881Speter editor->close_file = file_close; 427251881Speter 428251881Speter SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton, 429251881Speter editor, &eb, 430251881Speter &wrapped_editor, &wrapped_baton, 431251881Speter scratch_pool)); 432251881Speter 433251881Speter SVN_ERR(svn_ra_do_update3(ra_session, &reporter, &reporter_baton, 434251881Speter location->rev, "", svn_depth_infinity, 435251881Speter FALSE, FALSE, wrapped_editor, wrapped_baton, 436251881Speter scratch_pool, scratch_pool)); 437251881Speter 438251881Speter SVN_ERR(reporter->set_path(reporter_baton, "", location->rev, depth, 439251881Speter TRUE /* incomplete */, 440251881Speter NULL, scratch_pool)); 441251881Speter 442251881Speter SVN_ERR(reporter->finish_report(reporter_baton, scratch_pool)); 443251881Speter 444251881Speter return SVN_NO_ERROR; 445251881Speter} 446251881Speter 447251881Speter 448251881Spetersvn_error_t * 449251881Spetersvn_client__copy_foreign(const char *url, 450251881Speter const char *dst_abspath, 451251881Speter svn_opt_revision_t *peg_revision, 452251881Speter svn_opt_revision_t *revision, 453251881Speter svn_depth_t depth, 454251881Speter svn_boolean_t make_parents, 455251881Speter svn_boolean_t already_locked, 456251881Speter svn_client_ctx_t *ctx, 457251881Speter apr_pool_t *scratch_pool) 458251881Speter{ 459251881Speter svn_ra_session_t *ra_session; 460251881Speter svn_client__pathrev_t *loc; 461251881Speter svn_node_kind_t kind; 462251881Speter svn_node_kind_t wc_kind; 463251881Speter const char *dir_abspath; 464251881Speter 465251881Speter SVN_ERR_ASSERT(svn_path_is_url(url)); 466251881Speter SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath)); 467251881Speter 468251881Speter /* Do we need to validate/update revisions? */ 469251881Speter 470251881Speter SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc, 471251881Speter url, NULL, 472251881Speter peg_revision, 473251881Speter revision, ctx, 474251881Speter scratch_pool)); 475251881Speter 476251881Speter SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, scratch_pool)); 477251881Speter 478251881Speter if (kind != svn_node_file && kind != svn_node_dir) 479251881Speter return svn_error_createf( 480251881Speter SVN_ERR_ILLEGAL_TARGET, NULL, 481251881Speter _("'%s' is not a valid location inside a repository"), 482251881Speter url); 483251881Speter 484251881Speter SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dst_abspath, FALSE, TRUE, 485251881Speter scratch_pool)); 486251881Speter 487251881Speter if (wc_kind != svn_node_none) 488251881Speter { 489251881Speter return svn_error_createf( 490251881Speter SVN_ERR_ENTRY_EXISTS, NULL, 491251881Speter _("'%s' is already under version control"), 492251881Speter svn_dirent_local_style(dst_abspath, scratch_pool)); 493251881Speter } 494251881Speter 495251881Speter dir_abspath = svn_dirent_dirname(dst_abspath, scratch_pool); 496251881Speter SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dir_abspath, 497251881Speter FALSE, FALSE, scratch_pool)); 498251881Speter 499251881Speter if (wc_kind == svn_node_none) 500251881Speter { 501251881Speter if (make_parents) 502251881Speter SVN_ERR(svn_client__make_local_parents(dir_abspath, make_parents, ctx, 503251881Speter scratch_pool)); 504251881Speter 505251881Speter SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dir_abspath, 506251881Speter FALSE, FALSE, scratch_pool)); 507251881Speter } 508251881Speter 509251881Speter if (wc_kind != svn_node_dir) 510251881Speter return svn_error_createf( 511251881Speter SVN_ERR_ENTRY_NOT_FOUND, NULL, 512251881Speter _("Can't add '%s', because no parent directory is found"), 513251881Speter svn_dirent_local_style(dst_abspath, scratch_pool)); 514251881Speter 515251881Speter 516251881Speter if (kind == svn_node_file) 517251881Speter { 518251881Speter svn_stream_t *target; 519251881Speter apr_hash_t *props; 520251881Speter apr_hash_index_t *hi; 521251881Speter SVN_ERR(svn_stream_open_writable(&target, dst_abspath, scratch_pool, 522251881Speter scratch_pool)); 523251881Speter 524251881Speter SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev, target, NULL, &props, 525251881Speter scratch_pool)); 526251881Speter 527251881Speter if (props != NULL) 528251881Speter for (hi = apr_hash_first(scratch_pool, props); hi; 529251881Speter hi = apr_hash_next(hi)) 530251881Speter { 531299742Sdim const char *name = apr_hash_this_key(hi); 532251881Speter 533251881Speter if (svn_property_kind2(name) != svn_prop_regular_kind 534251881Speter || ! strcmp(name, SVN_PROP_MERGEINFO)) 535251881Speter { 536251881Speter /* We can't handle DAV, ENTRY and merge specific props here */ 537251881Speter svn_hash_sets(props, name, NULL); 538251881Speter } 539251881Speter } 540251881Speter 541251881Speter if (!already_locked) 542251881Speter SVN_WC__CALL_WITH_WRITE_LOCK( 543299742Sdim svn_wc_add_from_disk3(ctx->wc_ctx, dst_abspath, props, 544299742Sdim TRUE /* skip checks */, 545251881Speter ctx->notify_func2, ctx->notify_baton2, 546251881Speter scratch_pool), 547251881Speter ctx->wc_ctx, dir_abspath, FALSE, scratch_pool); 548251881Speter else 549299742Sdim SVN_ERR(svn_wc_add_from_disk3(ctx->wc_ctx, dst_abspath, props, 550299742Sdim TRUE /* skip checks */, 551251881Speter ctx->notify_func2, ctx->notify_baton2, 552251881Speter scratch_pool)); 553251881Speter } 554251881Speter else 555251881Speter { 556251881Speter if (!already_locked) 557251881Speter SVN_WC__CALL_WITH_WRITE_LOCK( 558251881Speter copy_foreign_dir(ra_session, loc, 559251881Speter ctx->wc_ctx, dst_abspath, 560251881Speter depth, 561251881Speter ctx->notify_func2, ctx->notify_baton2, 562251881Speter ctx->cancel_func, ctx->cancel_baton, 563251881Speter scratch_pool), 564251881Speter ctx->wc_ctx, dir_abspath, FALSE, scratch_pool); 565251881Speter else 566251881Speter SVN_ERR(copy_foreign_dir(ra_session, loc, 567251881Speter ctx->wc_ctx, dst_abspath, 568251881Speter depth, 569251881Speter ctx->notify_func2, ctx->notify_baton2, 570251881Speter ctx->cancel_func, ctx->cancel_baton, 571251881Speter scratch_pool)); 572251881Speter } 573251881Speter 574251881Speter return SVN_NO_ERROR; 575251881Speter} 576