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
163251881Speter         with the svn_wc_add_from_disk2() 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,
176251881Speter                               NULL, NULL, /* Cancelation */
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 */
216251881Speter  SVN_ERR(svn_wc_add_from_disk2(db->eb->wc_ctx,
217251881Speter                                db->local_abspath,
218251881Speter                                db->properties,
219251881Speter                                db->eb->notify_func,
220251881Speter                                db->eb->notify_baton,
221251881Speter                                scratch_pool));
222251881Speter
223251881Speter  return SVN_NO_ERROR;
224251881Speter}
225251881Speter
226251881Speterstatic svn_error_t *
227251881Speterdir_close(void *dir_baton,
228251881Speter          apr_pool_t *scratch_pool)
229251881Speter{
230251881Speter  struct dir_baton_t *db = dir_baton;
231251881Speter  /*struct edit_baton_t *eb = db->eb;*/
232251881Speter
233251881Speter  SVN_ERR(ensure_added(db, scratch_pool));
234251881Speter
235251881Speter  SVN_ERR(maybe_done(db));
236251881Speter
237251881Speter  return SVN_NO_ERROR;
238251881Speter}
239251881Speter
240251881Speterstruct file_baton_t
241251881Speter{
242251881Speter  apr_pool_t *pool;
243251881Speter
244251881Speter  struct dir_baton_t *pb;
245251881Speter  struct edit_baton_t *eb;
246251881Speter
247251881Speter  const char *local_abspath;
248251881Speter  apr_hash_t *properties;
249251881Speter
250251881Speter  svn_boolean_t writing;
251251881Speter  unsigned char digest[APR_MD5_DIGESTSIZE];
252251881Speter
253251881Speter  const char *tmp_path;
254251881Speter};
255251881Speter
256251881Speterstatic svn_error_t *
257251881Speterfile_add(const char *path,
258251881Speter         void *parent_baton,
259251881Speter         const char *copyfrom_path,
260251881Speter         svn_revnum_t copyfrom_revision,
261251881Speter         apr_pool_t *result_pool,
262251881Speter         void **file_baton)
263251881Speter{
264251881Speter  struct dir_baton_t *pb = parent_baton;
265251881Speter  struct edit_baton_t *eb = pb->eb;
266251881Speter  apr_pool_t *file_pool = svn_pool_create(pb->pool);
267251881Speter  struct file_baton_t *fb = apr_pcalloc(file_pool, sizeof(*fb));
268251881Speter  svn_boolean_t under_root;
269251881Speter
270251881Speter  pb->users++;
271251881Speter
272251881Speter  fb->pool = file_pool;
273251881Speter  fb->eb = eb;
274251881Speter  fb->pb = pb;
275251881Speter
276251881Speter  SVN_ERR(svn_dirent_is_under_root(&under_root, &fb->local_abspath,
277251881Speter                                   eb->anchor_abspath, path, fb->pool));
278251881Speter  if (! under_root)
279251881Speter    {
280251881Speter      return svn_error_createf(
281251881Speter                    SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
282251881Speter                    _("Path '%s' is not in the working copy"),
283251881Speter                    svn_dirent_local_style(path, fb->pool));
284251881Speter    }
285251881Speter
286251881Speter  *file_baton = fb;
287251881Speter  return SVN_NO_ERROR;
288251881Speter}
289251881Speter
290251881Speterstatic svn_error_t *
291251881Speterfile_change_prop(void *file_baton,
292251881Speter                 const char *name,
293251881Speter                 const svn_string_t *value,
294251881Speter                 apr_pool_t *scratch_pool)
295251881Speter{
296251881Speter  struct file_baton_t *fb = file_baton;
297251881Speter  svn_prop_kind_t prop_kind;
298251881Speter
299251881Speter  prop_kind = svn_property_kind2(name);
300251881Speter
301251881Speter  if (prop_kind != svn_prop_regular_kind
302251881Speter      || ! strcmp(name, SVN_PROP_MERGEINFO))
303251881Speter    {
304251881Speter      /* We can't handle DAV, ENTRY and merge specific props here */
305251881Speter      return SVN_NO_ERROR;
306251881Speter    }
307251881Speter
308251881Speter  /* We store all properties in the hash for immediate addition
309251881Speter      with the svn_wc_add_from_disk2() call */
310251881Speter  if (! fb->properties)
311251881Speter    fb->properties = apr_hash_make(fb->pool);
312251881Speter
313251881Speter  if (value != NULL)
314251881Speter    svn_hash_sets(fb->properties, apr_pstrdup(fb->pool, name),
315251881Speter                  svn_string_dup(value, fb->pool));
316251881Speter
317251881Speter  return SVN_NO_ERROR;
318251881Speter}
319251881Speter
320251881Speterstatic svn_error_t *
321251881Speterfile_textdelta(void *file_baton,
322251881Speter               const char *base_checksum,
323251881Speter               apr_pool_t *result_pool,
324251881Speter               svn_txdelta_window_handler_t *handler,
325251881Speter               void **handler_baton)
326251881Speter{
327251881Speter  struct file_baton_t *fb = file_baton;
328251881Speter  svn_stream_t *target;
329251881Speter
330251881Speter  SVN_ERR_ASSERT(! fb->writing);
331251881Speter
332251881Speter  SVN_ERR(svn_stream_open_writable(&target, fb->local_abspath, fb->pool,
333251881Speter                                   fb->pool));
334251881Speter
335251881Speter  fb->writing = TRUE;
336251881Speter  svn_txdelta_apply(svn_stream_empty(fb->pool) /* source */,
337251881Speter                    target,
338251881Speter                    fb->digest,
339251881Speter                    fb->local_abspath,
340251881Speter                    fb->pool,
341251881Speter                    /* Provide the handler directly */
342251881Speter                    handler, handler_baton);
343251881Speter
344251881Speter  return SVN_NO_ERROR;
345251881Speter}
346251881Speter
347251881Speterstatic svn_error_t *
348251881Speterfile_close(void *file_baton,
349251881Speter           const char *text_checksum,
350251881Speter           apr_pool_t *scratch_pool)
351251881Speter{
352251881Speter  struct file_baton_t *fb = file_baton;
353251881Speter  struct edit_baton_t *eb = fb->eb;
354251881Speter  struct dir_baton_t *pb = fb->pb;
355251881Speter
356251881Speter  SVN_ERR(ensure_added(pb, fb->pool));
357251881Speter
358251881Speter  if (text_checksum)
359251881Speter    {
360251881Speter      svn_checksum_t *expected_checksum;
361251881Speter      svn_checksum_t *actual_checksum;
362251881Speter
363251881Speter      SVN_ERR(svn_checksum_parse_hex(&expected_checksum, svn_checksum_md5,
364251881Speter                                     text_checksum, fb->pool));
365251881Speter      actual_checksum = svn_checksum__from_digest_md5(fb->digest, fb->pool);
366251881Speter
367251881Speter      if (! svn_checksum_match(expected_checksum, actual_checksum))
368251881Speter        return svn_error_trace(
369251881Speter                    svn_checksum_mismatch_err(expected_checksum,
370251881Speter                                              actual_checksum,
371251881Speter                                              fb->pool,
372251881Speter                                         _("Checksum mismatch for '%s'"),
373251881Speter                                              svn_dirent_local_style(
374251881Speter                                                    fb->local_abspath,
375251881Speter                                                    fb->pool)));
376251881Speter    }
377251881Speter
378251881Speter  SVN_ERR(svn_wc_add_from_disk2(eb->wc_ctx, fb->local_abspath, fb->properties,
379251881Speter                                eb->notify_func, eb->notify_baton,
380251881Speter                                fb->pool));
381251881Speter
382251881Speter  svn_pool_destroy(fb->pool);
383251881Speter  SVN_ERR(maybe_done(pb));
384251881Speter
385251881Speter  return SVN_NO_ERROR;
386251881Speter}
387251881Speter
388251881Speterstatic svn_error_t *
389251881Spetercopy_foreign_dir(svn_ra_session_t *ra_session,
390251881Speter                 svn_client__pathrev_t *location,
391251881Speter                 svn_wc_context_t *wc_ctx,
392251881Speter                 const char *dst_abspath,
393251881Speter                 svn_depth_t depth,
394251881Speter                 svn_wc_notify_func2_t notify_func,
395251881Speter                 void *notify_baton,
396251881Speter                 svn_cancel_func_t cancel_func,
397251881Speter                 void *cancel_baton,
398251881Speter                 apr_pool_t *scratch_pool)
399251881Speter{
400251881Speter  struct edit_baton_t eb;
401251881Speter  svn_delta_editor_t *editor = svn_delta_default_editor(scratch_pool);
402251881Speter  const svn_delta_editor_t *wrapped_editor;
403251881Speter  void *wrapped_baton;
404251881Speter  const svn_ra_reporter3_t *reporter;
405251881Speter  void *reporter_baton;
406251881Speter
407251881Speter  eb.pool = scratch_pool;
408251881Speter  eb.anchor_abspath = dst_abspath;
409251881Speter
410251881Speter  eb.wc_ctx = wc_ctx;
411251881Speter  eb.notify_func = notify_func;
412251881Speter  eb.notify_baton  = notify_baton;
413251881Speter
414251881Speter  editor->open_root = edit_open;
415251881Speter  editor->close_edit = edit_close;
416251881Speter
417251881Speter  editor->add_directory = dir_add;
418251881Speter  editor->change_dir_prop = dir_change_prop;
419251881Speter  editor->close_directory = dir_close;
420251881Speter
421251881Speter  editor->add_file = file_add;
422251881Speter  editor->change_file_prop = file_change_prop;
423251881Speter  editor->apply_textdelta = file_textdelta;
424251881Speter  editor->close_file = file_close;
425251881Speter
426251881Speter  SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
427251881Speter                                            editor, &eb,
428251881Speter                                            &wrapped_editor, &wrapped_baton,
429251881Speter                                            scratch_pool));
430251881Speter
431251881Speter  SVN_ERR(svn_ra_do_update3(ra_session, &reporter, &reporter_baton,
432251881Speter                            location->rev, "", svn_depth_infinity,
433251881Speter                            FALSE, FALSE, wrapped_editor, wrapped_baton,
434251881Speter                            scratch_pool, scratch_pool));
435251881Speter
436251881Speter  SVN_ERR(reporter->set_path(reporter_baton, "", location->rev, depth,
437251881Speter                             TRUE /* incomplete */,
438251881Speter                             NULL, scratch_pool));
439251881Speter
440251881Speter  SVN_ERR(reporter->finish_report(reporter_baton, scratch_pool));
441251881Speter
442251881Speter  return SVN_NO_ERROR;
443251881Speter}
444251881Speter
445251881Speter
446251881Spetersvn_error_t *
447251881Spetersvn_client__copy_foreign(const char *url,
448251881Speter                         const char *dst_abspath,
449251881Speter                         svn_opt_revision_t *peg_revision,
450251881Speter                         svn_opt_revision_t *revision,
451251881Speter                         svn_depth_t depth,
452251881Speter                         svn_boolean_t make_parents,
453251881Speter                         svn_boolean_t already_locked,
454251881Speter                         svn_client_ctx_t *ctx,
455251881Speter                         apr_pool_t *scratch_pool)
456251881Speter{
457251881Speter  svn_ra_session_t *ra_session;
458251881Speter  svn_client__pathrev_t *loc;
459251881Speter  svn_node_kind_t kind;
460251881Speter  svn_node_kind_t wc_kind;
461251881Speter  const char *dir_abspath;
462251881Speter
463251881Speter  SVN_ERR_ASSERT(svn_path_is_url(url));
464251881Speter  SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
465251881Speter
466251881Speter  /* Do we need to validate/update revisions? */
467251881Speter
468251881Speter  SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
469251881Speter                                            url, NULL,
470251881Speter                                            peg_revision,
471251881Speter                                            revision, ctx,
472251881Speter                                            scratch_pool));
473251881Speter
474251881Speter  SVN_ERR(svn_ra_check_path(ra_session, "", loc->rev, &kind, scratch_pool));
475251881Speter
476251881Speter  if (kind != svn_node_file && kind != svn_node_dir)
477251881Speter    return svn_error_createf(
478251881Speter                SVN_ERR_ILLEGAL_TARGET, NULL,
479251881Speter                _("'%s' is not a valid location inside a repository"),
480251881Speter                url);
481251881Speter
482251881Speter  SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dst_abspath, FALSE, TRUE,
483251881Speter                            scratch_pool));
484251881Speter
485251881Speter  if (wc_kind != svn_node_none)
486251881Speter    {
487251881Speter      return svn_error_createf(
488251881Speter                SVN_ERR_ENTRY_EXISTS, NULL,
489251881Speter                _("'%s' is already under version control"),
490251881Speter                svn_dirent_local_style(dst_abspath, scratch_pool));
491251881Speter    }
492251881Speter
493251881Speter  dir_abspath = svn_dirent_dirname(dst_abspath, scratch_pool);
494251881Speter  SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dir_abspath,
495251881Speter                            FALSE, FALSE, scratch_pool));
496251881Speter
497251881Speter  if (wc_kind == svn_node_none)
498251881Speter    {
499251881Speter      if (make_parents)
500251881Speter        SVN_ERR(svn_client__make_local_parents(dir_abspath, make_parents, ctx,
501251881Speter                                               scratch_pool));
502251881Speter
503251881Speter      SVN_ERR(svn_wc_read_kind2(&wc_kind, ctx->wc_ctx, dir_abspath,
504251881Speter                                FALSE, FALSE, scratch_pool));
505251881Speter    }
506251881Speter
507251881Speter  if (wc_kind != svn_node_dir)
508251881Speter    return svn_error_createf(
509251881Speter                SVN_ERR_ENTRY_NOT_FOUND, NULL,
510251881Speter                _("Can't add '%s', because no parent directory is found"),
511251881Speter                svn_dirent_local_style(dst_abspath, scratch_pool));
512251881Speter
513251881Speter
514251881Speter  if (kind == svn_node_file)
515251881Speter    {
516251881Speter      svn_stream_t *target;
517251881Speter      apr_hash_t *props;
518251881Speter      apr_hash_index_t *hi;
519251881Speter      SVN_ERR(svn_stream_open_writable(&target, dst_abspath, scratch_pool,
520251881Speter                                       scratch_pool));
521251881Speter
522251881Speter      SVN_ERR(svn_ra_get_file(ra_session, "", loc->rev, target, NULL, &props,
523251881Speter                              scratch_pool));
524251881Speter
525251881Speter      if (props != NULL)
526251881Speter        for (hi = apr_hash_first(scratch_pool, props); hi;
527251881Speter             hi = apr_hash_next(hi))
528251881Speter          {
529251881Speter            const char *name = svn__apr_hash_index_key(hi);
530251881Speter
531251881Speter            if (svn_property_kind2(name) != svn_prop_regular_kind
532251881Speter                || ! strcmp(name, SVN_PROP_MERGEINFO))
533251881Speter              {
534251881Speter                /* We can't handle DAV, ENTRY and merge specific props here */
535251881Speter                svn_hash_sets(props, name, NULL);
536251881Speter              }
537251881Speter          }
538251881Speter
539251881Speter      if (!already_locked)
540251881Speter        SVN_WC__CALL_WITH_WRITE_LOCK(
541251881Speter              svn_wc_add_from_disk2(ctx->wc_ctx, dst_abspath, props,
542251881Speter                                    ctx->notify_func2, ctx->notify_baton2,
543251881Speter                                    scratch_pool),
544251881Speter              ctx->wc_ctx, dir_abspath, FALSE, scratch_pool);
545251881Speter      else
546251881Speter        SVN_ERR(svn_wc_add_from_disk2(ctx->wc_ctx, dst_abspath, props,
547251881Speter                                      ctx->notify_func2, ctx->notify_baton2,
548251881Speter                                      scratch_pool));
549251881Speter    }
550251881Speter  else
551251881Speter    {
552251881Speter      if (!already_locked)
553251881Speter        SVN_WC__CALL_WITH_WRITE_LOCK(
554251881Speter              copy_foreign_dir(ra_session, loc,
555251881Speter                               ctx->wc_ctx, dst_abspath,
556251881Speter                               depth,
557251881Speter                               ctx->notify_func2, ctx->notify_baton2,
558251881Speter                               ctx->cancel_func, ctx->cancel_baton,
559251881Speter                               scratch_pool),
560251881Speter              ctx->wc_ctx, dir_abspath, FALSE, scratch_pool);
561251881Speter      else
562251881Speter        SVN_ERR(copy_foreign_dir(ra_session, loc,
563251881Speter                                 ctx->wc_ctx, dst_abspath,
564251881Speter                                 depth,
565251881Speter                                 ctx->notify_func2, ctx->notify_baton2,
566251881Speter                                 ctx->cancel_func, ctx->cancel_baton,
567251881Speter                                 scratch_pool));
568251881Speter    }
569251881Speter
570251881Speter  return SVN_NO_ERROR;
571251881Speter}
572