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