1/*
2 * deprecated.c:  holding file for all deprecated APIs.
3 *                "we can't lose 'em, but we can shun 'em!"
4 *
5 * ====================================================================
6 *    Licensed to the Apache Software Foundation (ASF) under one
7 *    or more contributor license agreements.  See the NOTICE file
8 *    distributed with this work for additional information
9 *    regarding copyright ownership.  The ASF licenses this file
10 *    to you under the Apache License, Version 2.0 (the
11 *    "License"); you may not use this file except in compliance
12 *    with the License.  You may obtain a copy of the License at
13 *
14 *      http://www.apache.org/licenses/LICENSE-2.0
15 *
16 *    Unless required by applicable law or agreed to in writing,
17 *    software distributed under the License is distributed on an
18 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19 *    KIND, either express or implied.  See the License for the
20 *    specific language governing permissions and limitations
21 *    under the License.
22 * ====================================================================
23 */
24
25/* ==================================================================== */
26
27
28
29/*** Includes. ***/
30
31/* We define this here to remove any further warnings about the usage of
32   deprecated functions in this file. */
33#define SVN_DEPRECATED
34
35#include <string.h>
36#include "svn_client.h"
37#include "svn_path.h"
38#include "svn_compat.h"
39#include "svn_hash.h"
40#include "svn_props.h"
41#include "svn_utf.h"
42#include "svn_string.h"
43#include "svn_pools.h"
44
45#include "client.h"
46#include "mergeinfo.h"
47
48#include "private/svn_opt_private.h"
49#include "private/svn_wc_private.h"
50#include "svn_private_config.h"
51
52
53
54
55/*** Code. ***/
56
57
58/* Baton for capture_commit_info() */
59struct capture_baton_t {
60  svn_commit_info_t **info;
61  apr_pool_t *pool;
62};
63
64
65/* Callback which implements svn_commit_callback2_t for use with some
66   backward compat functions. */
67static svn_error_t *
68capture_commit_info(const svn_commit_info_t *commit_info,
69                    void *baton,
70                    apr_pool_t *pool)
71{
72  struct capture_baton_t *cb = baton;
73
74  *(cb->info) = svn_commit_info_dup(commit_info, cb->pool);
75
76  return SVN_NO_ERROR;
77}
78
79
80/*** From add.c ***/
81svn_error_t *
82svn_client_add4(const char *path,
83                svn_depth_t depth,
84                svn_boolean_t force,
85                svn_boolean_t no_ignore,
86                svn_boolean_t add_parents,
87                svn_client_ctx_t *ctx,
88                apr_pool_t *pool)
89{
90  return svn_client_add5(path, depth, force, no_ignore, FALSE, add_parents,
91                         ctx, pool);
92}
93
94svn_error_t *
95svn_client_add3(const char *path,
96                svn_boolean_t recursive,
97                svn_boolean_t force,
98                svn_boolean_t no_ignore,
99                svn_client_ctx_t *ctx,
100                apr_pool_t *pool)
101{
102  return svn_client_add4(path, SVN_DEPTH_INFINITY_OR_EMPTY(recursive),
103                         force, no_ignore, FALSE, ctx,
104                         pool);
105}
106
107svn_error_t *
108svn_client_add2(const char *path,
109                svn_boolean_t recursive,
110                svn_boolean_t force,
111                svn_client_ctx_t *ctx,
112                apr_pool_t *pool)
113{
114  return svn_client_add3(path, recursive, force, FALSE, ctx, pool);
115}
116
117svn_error_t *
118svn_client_add(const char *path,
119               svn_boolean_t recursive,
120               svn_client_ctx_t *ctx,
121               apr_pool_t *pool)
122{
123  return svn_client_add3(path, recursive, FALSE, FALSE, ctx, pool);
124}
125
126svn_error_t *
127svn_client_mkdir3(svn_commit_info_t **commit_info_p,
128                  const apr_array_header_t *paths,
129                  svn_boolean_t make_parents,
130                  const apr_hash_t *revprop_table,
131                  svn_client_ctx_t *ctx,
132                  apr_pool_t *pool)
133{
134  struct capture_baton_t cb;
135
136  cb.info = commit_info_p;
137  cb.pool = pool;
138
139  return svn_client_mkdir4(paths, make_parents, revprop_table,
140                           capture_commit_info, &cb, ctx, pool);
141}
142
143svn_error_t *
144svn_client_mkdir2(svn_commit_info_t **commit_info_p,
145                  const apr_array_header_t *paths,
146                  svn_client_ctx_t *ctx,
147                  apr_pool_t *pool)
148{
149  return svn_client_mkdir3(commit_info_p, paths, FALSE, NULL, ctx, pool);
150}
151
152
153svn_error_t *
154svn_client_mkdir(svn_client_commit_info_t **commit_info_p,
155                 const apr_array_header_t *paths,
156                 svn_client_ctx_t *ctx,
157                 apr_pool_t *pool)
158{
159  svn_commit_info_t *commit_info = NULL;
160  svn_error_t *err;
161
162  err = svn_client_mkdir2(&commit_info, paths, ctx, pool);
163  /* These structs have the same layout for the common fields. */
164  *commit_info_p = (svn_client_commit_info_t *) commit_info;
165  return svn_error_trace(err);
166}
167
168/*** From blame.c ***/
169
170struct blame_receiver_wrapper_baton2 {
171  void *baton;
172  svn_client_blame_receiver2_t receiver;
173};
174
175static svn_error_t *
176blame_wrapper_receiver2(void *baton,
177   svn_revnum_t start_revnum,
178   svn_revnum_t end_revnum,
179   apr_int64_t line_no,
180   svn_revnum_t revision,
181   apr_hash_t *rev_props,
182   svn_revnum_t merged_revision,
183   apr_hash_t *merged_rev_props,
184   const char *merged_path,
185   const char *line,
186   svn_boolean_t local_change,
187   apr_pool_t *pool)
188{
189  struct blame_receiver_wrapper_baton2 *brwb = baton;
190  const char *author = NULL;
191  const char *date = NULL;
192  const char *merged_author = NULL;
193  const char *merged_date = NULL;
194
195  if (rev_props != NULL)
196    {
197      author = svn_prop_get_value(rev_props, SVN_PROP_REVISION_AUTHOR);
198      date = svn_prop_get_value(rev_props, SVN_PROP_REVISION_DATE);
199    }
200  if (merged_rev_props != NULL)
201    {
202      merged_author = svn_prop_get_value(merged_rev_props,
203                                         SVN_PROP_REVISION_AUTHOR);
204      merged_date = svn_prop_get_value(merged_rev_props,
205                                       SVN_PROP_REVISION_DATE);
206    }
207
208  if (brwb->receiver)
209    return brwb->receiver(brwb->baton, line_no, revision, author, date,
210                          merged_revision, merged_author, merged_date,
211                          merged_path, line, pool);
212
213  return SVN_NO_ERROR;
214}
215
216svn_error_t *
217svn_client_blame4(const char *target,
218                  const svn_opt_revision_t *peg_revision,
219                  const svn_opt_revision_t *start,
220                  const svn_opt_revision_t *end,
221                  const svn_diff_file_options_t *diff_options,
222                  svn_boolean_t ignore_mime_type,
223                  svn_boolean_t include_merged_revisions,
224                  svn_client_blame_receiver2_t receiver,
225                  void *receiver_baton,
226                  svn_client_ctx_t *ctx,
227                  apr_pool_t *pool)
228{
229  struct blame_receiver_wrapper_baton2 baton;
230
231  baton.receiver = receiver;
232  baton.baton = receiver_baton;
233
234  return svn_client_blame5(target, peg_revision, start, end, diff_options,
235                           ignore_mime_type, include_merged_revisions,
236                           blame_wrapper_receiver2, &baton, ctx, pool);
237}
238
239
240/* Baton for use with wrap_blame_receiver */
241struct blame_receiver_wrapper_baton {
242  void *baton;
243  svn_client_blame_receiver_t receiver;
244};
245
246/* This implements svn_client_blame_receiver2_t */
247static svn_error_t *
248blame_wrapper_receiver(void *baton,
249                       apr_int64_t line_no,
250                       svn_revnum_t revision,
251                       const char *author,
252                       const char *date,
253                       svn_revnum_t merged_revision,
254                       const char *merged_author,
255                       const char *merged_date,
256                       const char *merged_path,
257                       const char *line,
258                       apr_pool_t *pool)
259{
260  struct blame_receiver_wrapper_baton *brwb = baton;
261
262  if (brwb->receiver)
263    return brwb->receiver(brwb->baton,
264                          line_no, revision, author, date, line, pool);
265
266  return SVN_NO_ERROR;
267}
268
269static void
270wrap_blame_receiver(svn_client_blame_receiver2_t *receiver2,
271                    void **receiver2_baton,
272                    svn_client_blame_receiver_t receiver,
273                    void *receiver_baton,
274                    apr_pool_t *pool)
275{
276  struct blame_receiver_wrapper_baton *brwb = apr_palloc(pool, sizeof(*brwb));
277
278  /* Set the user provided old format callback in the baton. */
279  brwb->baton = receiver_baton;
280  brwb->receiver = receiver;
281
282  *receiver2_baton = brwb;
283  *receiver2 = blame_wrapper_receiver;
284}
285
286svn_error_t *
287svn_client_blame3(const char *target,
288                  const svn_opt_revision_t *peg_revision,
289                  const svn_opt_revision_t *start,
290                  const svn_opt_revision_t *end,
291                  const svn_diff_file_options_t *diff_options,
292                  svn_boolean_t ignore_mime_type,
293                  svn_client_blame_receiver_t receiver,
294                  void *receiver_baton,
295                  svn_client_ctx_t *ctx,
296                  apr_pool_t *pool)
297{
298  svn_client_blame_receiver2_t receiver2;
299  void *receiver2_baton;
300
301  wrap_blame_receiver(&receiver2, &receiver2_baton, receiver, receiver_baton,
302                      pool);
303
304  return svn_client_blame4(target, peg_revision, start, end, diff_options,
305                           ignore_mime_type, FALSE, receiver2, receiver2_baton,
306                           ctx, pool);
307}
308
309/* svn_client_blame3 guarantees 'no EOL chars' as part of the receiver
310   LINE argument.  Older versions depend on the fact that if a CR is
311   required, that CR is already part of the LINE data.
312
313   Because of this difference, we need to trap old receivers and append
314   a CR to LINE before passing it on to the actual receiver on platforms
315   which want CRLF line termination.
316
317*/
318
319struct wrapped_receiver_baton_s
320{
321  svn_client_blame_receiver_t orig_receiver;
322  void *orig_baton;
323};
324
325static svn_error_t *
326wrapped_receiver(void *baton,
327                 apr_int64_t line_no,
328                 svn_revnum_t revision,
329                 const char *author,
330                 const char *date,
331                 const char *line,
332                 apr_pool_t *pool)
333{
334  struct wrapped_receiver_baton_s *b = baton;
335  svn_stringbuf_t *expanded_line = svn_stringbuf_create(line, pool);
336
337  svn_stringbuf_appendbyte(expanded_line, '\r');
338
339  return b->orig_receiver(b->orig_baton, line_no, revision, author,
340                          date, expanded_line->data, pool);
341}
342
343static void
344wrap_pre_blame3_receiver(svn_client_blame_receiver_t *receiver,
345                         void **receiver_baton,
346                         apr_pool_t *pool)
347{
348  if (sizeof(APR_EOL_STR) == 3)
349    {
350      struct wrapped_receiver_baton_s *b = apr_palloc(pool,sizeof(*b));
351
352      b->orig_receiver = *receiver;
353      b->orig_baton = *receiver_baton;
354
355      *receiver_baton = b;
356      *receiver = wrapped_receiver;
357    }
358}
359
360svn_error_t *
361svn_client_blame2(const char *target,
362                  const svn_opt_revision_t *peg_revision,
363                  const svn_opt_revision_t *start,
364                  const svn_opt_revision_t *end,
365                  svn_client_blame_receiver_t receiver,
366                  void *receiver_baton,
367                  svn_client_ctx_t *ctx,
368                  apr_pool_t *pool)
369{
370  wrap_pre_blame3_receiver(&receiver, &receiver_baton, pool);
371  return svn_client_blame3(target, peg_revision, start, end,
372                           svn_diff_file_options_create(pool), FALSE,
373                           receiver, receiver_baton, ctx, pool);
374}
375svn_error_t *
376svn_client_blame(const char *target,
377                 const svn_opt_revision_t *start,
378                 const svn_opt_revision_t *end,
379                 svn_client_blame_receiver_t receiver,
380                 void *receiver_baton,
381                 svn_client_ctx_t *ctx,
382                 apr_pool_t *pool)
383{
384  wrap_pre_blame3_receiver(&receiver, &receiver_baton, pool);
385  return svn_client_blame2(target, end, start, end,
386                           receiver, receiver_baton, ctx, pool);
387}
388
389/*** From cmdline.c ***/
390svn_error_t *
391svn_client_args_to_target_array(apr_array_header_t **targets_p,
392                                apr_getopt_t *os,
393                                const apr_array_header_t *known_targets,
394                                svn_client_ctx_t *ctx,
395                                apr_pool_t *pool)
396{
397  return svn_client_args_to_target_array2(targets_p, os, known_targets, ctx,
398                                          FALSE, pool);
399}
400
401/*** From commit.c ***/
402svn_error_t *
403svn_client_import4(const char *path,
404                   const char *url,
405                   svn_depth_t depth,
406                   svn_boolean_t no_ignore,
407                   svn_boolean_t ignore_unknown_node_types,
408                   const apr_hash_t *revprop_table,
409                   svn_commit_callback2_t commit_callback,
410                   void *commit_baton,
411                   svn_client_ctx_t *ctx,
412                   apr_pool_t *pool)
413{
414  return svn_error_trace(svn_client_import5(path, url, depth, no_ignore,
415                                            FALSE, ignore_unknown_node_types,
416                                            revprop_table,
417                                            NULL, NULL,
418                                            commit_callback, commit_baton,
419                                            ctx, pool));
420}
421
422
423svn_error_t *
424svn_client_import3(svn_commit_info_t **commit_info_p,
425                   const char *path,
426                   const char *url,
427                   svn_depth_t depth,
428                   svn_boolean_t no_ignore,
429                   svn_boolean_t ignore_unknown_node_types,
430                   const apr_hash_t *revprop_table,
431                   svn_client_ctx_t *ctx,
432                   apr_pool_t *pool)
433{
434  struct capture_baton_t cb;
435
436  cb.info = commit_info_p;
437  cb.pool = pool;
438
439  return svn_client_import4(path, url, depth, no_ignore,
440                            ignore_unknown_node_types, revprop_table,
441                            capture_commit_info, &cb, ctx, pool);
442}
443
444svn_error_t *
445svn_client_import2(svn_commit_info_t **commit_info_p,
446                   const char *path,
447                   const char *url,
448                   svn_boolean_t nonrecursive,
449                   svn_boolean_t no_ignore,
450                   svn_client_ctx_t *ctx,
451                   apr_pool_t *pool)
452{
453  return svn_client_import3(commit_info_p,
454                            path, url,
455                            SVN_DEPTH_INFINITY_OR_FILES(! nonrecursive),
456                            no_ignore, FALSE, NULL, ctx, pool);
457}
458
459svn_error_t *
460svn_client_import(svn_client_commit_info_t **commit_info_p,
461                  const char *path,
462                  const char *url,
463                  svn_boolean_t nonrecursive,
464                  svn_client_ctx_t *ctx,
465                  apr_pool_t *pool)
466{
467  svn_commit_info_t *commit_info = NULL;
468  svn_error_t *err;
469
470  err = svn_client_import2(&commit_info,
471                           path, url, nonrecursive,
472                           FALSE, ctx, pool);
473  /* These structs have the same layout for the common fields. */
474  *commit_info_p = (svn_client_commit_info_t *) commit_info;
475  return svn_error_trace(err);
476}
477
478
479/* Wrapper notify_func2 function and baton for downgrading
480   svn_wc_notify_commit_copied and svn_wc_notify_commit_copied_replaced
481   to svn_wc_notify_commit_added and svn_wc_notify_commit_replaced,
482   respectively. */
483struct downgrade_commit_copied_notify_baton
484{
485  svn_wc_notify_func2_t orig_notify_func2;
486  void *orig_notify_baton2;
487};
488
489static void
490downgrade_commit_copied_notify_func(void *baton,
491                                    const svn_wc_notify_t *notify,
492                                    apr_pool_t *pool)
493{
494  struct downgrade_commit_copied_notify_baton *b = baton;
495
496  if (notify->action == svn_wc_notify_commit_copied)
497    {
498      svn_wc_notify_t *my_notify = svn_wc_dup_notify(notify, pool);
499      my_notify->action = svn_wc_notify_commit_added;
500      notify = my_notify;
501    }
502  else if (notify->action == svn_wc_notify_commit_copied_replaced)
503    {
504      svn_wc_notify_t *my_notify = svn_wc_dup_notify(notify, pool);
505      my_notify->action = svn_wc_notify_commit_replaced;
506      notify = my_notify;
507    }
508
509  /* Call the wrapped notification system (if any) with MY_NOTIFY,
510     which is either the original NOTIFY object, or a tweaked deep
511     copy thereof. */
512  if (b->orig_notify_func2)
513    b->orig_notify_func2(b->orig_notify_baton2, notify, pool);
514}
515
516svn_error_t *
517svn_client_commit5(const apr_array_header_t *targets,
518                   svn_depth_t depth,
519                   svn_boolean_t keep_locks,
520                   svn_boolean_t keep_changelists,
521                   svn_boolean_t commit_as_operations,
522                   const apr_array_header_t *changelists,
523                   const apr_hash_t *revprop_table,
524                   svn_commit_callback2_t commit_callback,
525                   void *commit_baton,
526                   svn_client_ctx_t *ctx,
527                   apr_pool_t *pool)
528{
529  return svn_client_commit6(targets, depth, keep_locks, keep_changelists,
530                            commit_as_operations,
531                            FALSE,  /* include_file_externals */
532                            FALSE, /* include_dir_externals */
533                            changelists, revprop_table, commit_callback,
534                            commit_baton, ctx, pool);
535}
536
537svn_error_t *
538svn_client_commit4(svn_commit_info_t **commit_info_p,
539                   const apr_array_header_t *targets,
540                   svn_depth_t depth,
541                   svn_boolean_t keep_locks,
542                   svn_boolean_t keep_changelists,
543                   const apr_array_header_t *changelists,
544                   const apr_hash_t *revprop_table,
545                   svn_client_ctx_t *ctx,
546                   apr_pool_t *pool)
547{
548  struct capture_baton_t cb;
549  struct downgrade_commit_copied_notify_baton notify_baton;
550  svn_error_t *err;
551
552  notify_baton.orig_notify_func2 = ctx->notify_func2;
553  notify_baton.orig_notify_baton2 = ctx->notify_baton2;
554
555  *commit_info_p = NULL;
556  cb.info = commit_info_p;
557  cb.pool = pool;
558
559  /* Swap out the notification system (if any) with a thin filtering
560     wrapper. */
561  if (ctx->notify_func2)
562    {
563      ctx->notify_func2 = downgrade_commit_copied_notify_func;
564      ctx->notify_baton2 = &notify_baton;
565    }
566
567  err = svn_client_commit5(targets, depth, keep_locks, keep_changelists, FALSE,
568                           changelists, revprop_table,
569                           capture_commit_info, &cb, ctx, pool);
570
571  /* Ensure that the original notification system is in place. */
572  ctx->notify_func2 = notify_baton.orig_notify_func2;
573  ctx->notify_baton2 = notify_baton.orig_notify_baton2;
574
575  SVN_ERR(err);
576
577  if (! *commit_info_p)
578    *commit_info_p = svn_create_commit_info(pool);
579
580  return SVN_NO_ERROR;
581}
582
583svn_error_t *
584svn_client_commit3(svn_commit_info_t **commit_info_p,
585                   const apr_array_header_t *targets,
586                   svn_boolean_t recurse,
587                   svn_boolean_t keep_locks,
588                   svn_client_ctx_t *ctx,
589                   apr_pool_t *pool)
590{
591  svn_depth_t depth = SVN_DEPTH_INFINITY_OR_EMPTY(recurse);
592
593  return svn_client_commit4(commit_info_p, targets, depth, keep_locks,
594                            FALSE, NULL, NULL, ctx, pool);
595}
596
597svn_error_t *
598svn_client_commit2(svn_client_commit_info_t **commit_info_p,
599                   const apr_array_header_t *targets,
600                   svn_boolean_t recurse,
601                   svn_boolean_t keep_locks,
602                   svn_client_ctx_t *ctx,
603                   apr_pool_t *pool)
604{
605  svn_commit_info_t *commit_info = NULL;
606  svn_error_t *err;
607
608  err = svn_client_commit3(&commit_info, targets, recurse, keep_locks,
609                           ctx, pool);
610  /* These structs have the same layout for the common fields. */
611  *commit_info_p = (svn_client_commit_info_t *) commit_info;
612  return svn_error_trace(err);
613}
614
615svn_error_t *
616svn_client_commit(svn_client_commit_info_t **commit_info_p,
617                  const apr_array_header_t *targets,
618                  svn_boolean_t nonrecursive,
619                  svn_client_ctx_t *ctx,
620                  apr_pool_t *pool)
621{
622  return svn_client_commit2(commit_info_p, targets,
623                            ! nonrecursive,
624                            TRUE,
625                            ctx, pool);
626}
627
628/*** From copy.c ***/
629svn_error_t *
630svn_client_copy6(const apr_array_header_t *sources,
631                 const char *dst_path,
632                 svn_boolean_t copy_as_child,
633                 svn_boolean_t make_parents,
634                 svn_boolean_t ignore_externals,
635                 const apr_hash_t *revprop_table,
636                 svn_commit_callback2_t commit_callback,
637                 void *commit_baton,
638                 svn_client_ctx_t *ctx,
639                 apr_pool_t *pool)
640{
641  return svn_error_trace(svn_client_copy7(sources, dst_path, copy_as_child,
642                                          make_parents, ignore_externals,
643                                          FALSE /* metadata_only */,
644                                          FALSE /* pin_externals */,
645                                          NULL /* externals_to_pin */,
646                                          revprop_table,
647                                          commit_callback, commit_baton,
648                                          ctx, pool));
649}
650
651svn_error_t *
652svn_client_copy5(svn_commit_info_t **commit_info_p,
653                 const apr_array_header_t *sources,
654                 const char *dst_path,
655                 svn_boolean_t copy_as_child,
656                 svn_boolean_t make_parents,
657                 svn_boolean_t ignore_externals,
658                 const apr_hash_t *revprop_table,
659                 svn_client_ctx_t *ctx,
660                 apr_pool_t *pool)
661{
662  struct capture_baton_t cb;
663
664  cb.info = commit_info_p;
665  cb.pool = pool;
666
667  return svn_client_copy6(sources, dst_path, copy_as_child, make_parents,
668                          ignore_externals, revprop_table,
669                          capture_commit_info, &cb, ctx, pool);
670}
671
672svn_error_t *
673svn_client_copy4(svn_commit_info_t **commit_info_p,
674                 const apr_array_header_t *sources,
675                 const char *dst_path,
676                 svn_boolean_t copy_as_child,
677                 svn_boolean_t make_parents,
678                 const apr_hash_t *revprop_table,
679                 svn_client_ctx_t *ctx,
680                 apr_pool_t *pool)
681{
682  return svn_client_copy5(commit_info_p, sources, dst_path, copy_as_child,
683                          make_parents, FALSE, revprop_table, ctx, pool);
684}
685
686svn_error_t *
687svn_client_copy3(svn_commit_info_t **commit_info_p,
688                 const char *src_path,
689                 const svn_opt_revision_t *src_revision,
690                 const char *dst_path,
691                 svn_client_ctx_t *ctx,
692                 apr_pool_t *pool)
693{
694  apr_array_header_t *sources = apr_array_make(pool, 1,
695                                  sizeof(const svn_client_copy_source_t *));
696  svn_client_copy_source_t copy_source;
697
698  copy_source.path = src_path;
699  copy_source.revision = src_revision;
700  copy_source.peg_revision = src_revision;
701
702  APR_ARRAY_PUSH(sources, const svn_client_copy_source_t *) = &copy_source;
703
704  return svn_client_copy4(commit_info_p, sources, dst_path, FALSE, FALSE,
705                          NULL, ctx, pool);
706}
707
708svn_error_t *
709svn_client_copy2(svn_commit_info_t **commit_info_p,
710                 const char *src_path,
711                 const svn_opt_revision_t *src_revision,
712                 const char *dst_path,
713                 svn_client_ctx_t *ctx,
714                 apr_pool_t *pool)
715{
716  svn_error_t *err;
717
718  err = svn_client_copy3(commit_info_p, src_path, src_revision,
719                         dst_path, ctx, pool);
720
721  /* If the target exists, try to copy the source as a child of the target.
722     This will obviously fail if target is not a directory, but that's exactly
723     what we want. */
724  if (err && (err->apr_err == SVN_ERR_ENTRY_EXISTS
725              || err->apr_err == SVN_ERR_FS_ALREADY_EXISTS))
726    {
727      const char *src_basename = svn_path_basename(src_path, pool);
728
729      svn_error_clear(err);
730
731      return svn_client_copy3(commit_info_p, src_path, src_revision,
732                              svn_path_join(dst_path, src_basename, pool),
733                              ctx, pool);
734    }
735
736  return svn_error_trace(err);
737}
738
739svn_error_t *
740svn_client_copy(svn_client_commit_info_t **commit_info_p,
741                const char *src_path,
742                const svn_opt_revision_t *src_revision,
743                const char *dst_path,
744                svn_client_ctx_t *ctx,
745                apr_pool_t *pool)
746{
747  svn_commit_info_t *commit_info = NULL;
748  svn_error_t *err;
749
750  err = svn_client_copy2(&commit_info, src_path, src_revision, dst_path,
751                         ctx, pool);
752  /* These structs have the same layout for the common fields. */
753  *commit_info_p = (svn_client_commit_info_t *) commit_info;
754  return svn_error_trace(err);
755}
756
757svn_error_t *
758svn_client_move6(const apr_array_header_t *src_paths,
759                 const char *dst_path,
760                 svn_boolean_t move_as_child,
761                 svn_boolean_t make_parents,
762                 const apr_hash_t *revprop_table,
763                 svn_commit_callback2_t commit_callback,
764                 void *commit_baton,
765                 svn_client_ctx_t *ctx,
766                 apr_pool_t *pool)
767{
768  return svn_error_trace(svn_client_move7(src_paths, dst_path,
769                                          move_as_child, make_parents,
770                                          TRUE /* allow_mixed_revisions */,
771                                          FALSE /* metadata_only */,
772                                          revprop_table,
773                                          commit_callback, commit_baton,
774                                          ctx, pool));
775}
776
777svn_error_t *
778svn_client_move5(svn_commit_info_t **commit_info_p,
779                 const apr_array_header_t *src_paths,
780                 const char *dst_path,
781                 svn_boolean_t force,
782                 svn_boolean_t move_as_child,
783                 svn_boolean_t make_parents,
784                 const apr_hash_t *revprop_table,
785                 svn_client_ctx_t *ctx,
786                 apr_pool_t *pool)
787{
788  struct capture_baton_t cb;
789
790  cb.info = commit_info_p;
791  cb.pool = pool;
792
793  return svn_client_move6(src_paths, dst_path, move_as_child,
794                          make_parents, revprop_table,
795                          capture_commit_info, &cb, ctx, pool);
796}
797
798svn_error_t *
799svn_client_move4(svn_commit_info_t **commit_info_p,
800                 const char *src_path,
801                 const char *dst_path,
802                 svn_boolean_t force,
803                 svn_client_ctx_t *ctx,
804                 apr_pool_t *pool)
805{
806  apr_array_header_t *src_paths =
807    apr_array_make(pool, 1, sizeof(const char *));
808  APR_ARRAY_PUSH(src_paths, const char *) = src_path;
809
810
811  return svn_client_move5(commit_info_p, src_paths, dst_path, force, FALSE,
812                          FALSE, NULL, ctx, pool);
813}
814
815svn_error_t *
816svn_client_move3(svn_commit_info_t **commit_info_p,
817                 const char *src_path,
818                 const char *dst_path,
819                 svn_boolean_t force,
820                 svn_client_ctx_t *ctx,
821                 apr_pool_t *pool)
822{
823  svn_error_t *err;
824
825  err = svn_client_move4(commit_info_p, src_path, dst_path, force, ctx, pool);
826
827  /* If the target exists, try to move the source as a child of the target.
828     This will obviously fail if target is not a directory, but that's exactly
829     what we want. */
830  if (err && (err->apr_err == SVN_ERR_ENTRY_EXISTS
831              || err->apr_err == SVN_ERR_FS_ALREADY_EXISTS))
832    {
833      const char *src_basename = svn_path_basename(src_path, pool);
834
835      svn_error_clear(err);
836
837      return svn_client_move4(commit_info_p, src_path,
838                              svn_path_join(dst_path, src_basename, pool),
839                              force, ctx, pool);
840    }
841
842  return svn_error_trace(err);
843}
844
845svn_error_t *
846svn_client_move2(svn_client_commit_info_t **commit_info_p,
847                 const char *src_path,
848                 const char *dst_path,
849                 svn_boolean_t force,
850                 svn_client_ctx_t *ctx,
851                 apr_pool_t *pool)
852{
853  svn_commit_info_t *commit_info = NULL;
854  svn_error_t *err;
855
856  err = svn_client_move3(&commit_info, src_path, dst_path, force, ctx, pool);
857  /* These structs have the same layout for the common fields. */
858  *commit_info_p = (svn_client_commit_info_t *) commit_info;
859  return svn_error_trace(err);
860}
861
862
863svn_error_t *
864svn_client_move(svn_client_commit_info_t **commit_info_p,
865                const char *src_path,
866                const svn_opt_revision_t *src_revision,
867                const char *dst_path,
868                svn_boolean_t force,
869                svn_client_ctx_t *ctx,
870                apr_pool_t *pool)
871{
872  /* It doesn't make sense to specify revisions in a move. */
873
874  /* ### todo: this check could fail wrongly.  For example,
875     someone could pass in an svn_opt_revision_number that just
876     happens to be the HEAD.  It's fair enough to punt then, IMHO,
877     and just demand that the user not specify a revision at all;
878     beats mucking up this function with RA calls and such. */
879  if (src_revision->kind != svn_opt_revision_unspecified
880      && src_revision->kind != svn_opt_revision_head)
881    {
882      return svn_error_create
883        (SVN_ERR_UNSUPPORTED_FEATURE, NULL,
884         _("Cannot specify revisions (except HEAD) with move operations"));
885    }
886
887  return svn_client_move2(commit_info_p, src_path, dst_path, force, ctx, pool);
888}
889
890/*** From delete.c ***/
891svn_error_t *
892svn_client_delete3(svn_commit_info_t **commit_info_p,
893                   const apr_array_header_t *paths,
894                   svn_boolean_t force,
895                   svn_boolean_t keep_local,
896                   const apr_hash_t *revprop_table,
897                   svn_client_ctx_t *ctx,
898                   apr_pool_t *pool)
899{
900  struct capture_baton_t cb;
901
902  cb.info = commit_info_p;
903  cb.pool = pool;
904
905  return svn_client_delete4(paths, force, keep_local, revprop_table,
906                            capture_commit_info, &cb, ctx, pool);
907}
908
909svn_error_t *
910svn_client_delete2(svn_commit_info_t **commit_info_p,
911                   const apr_array_header_t *paths,
912                   svn_boolean_t force,
913                   svn_client_ctx_t *ctx,
914                   apr_pool_t *pool)
915{
916  return svn_client_delete3(commit_info_p, paths, force, FALSE, NULL,
917                            ctx, pool);
918}
919
920svn_error_t *
921svn_client_delete(svn_client_commit_info_t **commit_info_p,
922                  const apr_array_header_t *paths,
923                  svn_boolean_t force,
924                  svn_client_ctx_t *ctx,
925                  apr_pool_t *pool)
926{
927  svn_commit_info_t *commit_info = NULL;
928  svn_error_t *err = NULL;
929
930  err = svn_client_delete2(&commit_info, paths, force, ctx, pool);
931  /* These structs have the same layout for the common fields. */
932  *commit_info_p = (svn_client_commit_info_t *) commit_info;
933  return svn_error_trace(err);
934}
935
936/*** From diff.c ***/
937
938svn_error_t *
939svn_client_diff5(const apr_array_header_t *diff_options,
940                 const char *path1,
941                 const svn_opt_revision_t *revision1,
942                 const char *path2,
943                 const svn_opt_revision_t *revision2,
944                 const char *relative_to_dir,
945                 svn_depth_t depth,
946                 svn_boolean_t ignore_ancestry,
947                 svn_boolean_t no_diff_deleted,
948                 svn_boolean_t show_copies_as_adds,
949                 svn_boolean_t ignore_content_type,
950                 svn_boolean_t use_git_diff_format,
951                 const char *header_encoding,
952                 apr_file_t *outfile,
953                 apr_file_t *errfile,
954                 const apr_array_header_t *changelists,
955                 svn_client_ctx_t *ctx,
956                 apr_pool_t *pool)
957{
958  svn_stream_t *outstream = svn_stream_from_aprfile2(outfile, TRUE, pool);
959  svn_stream_t *errstream = svn_stream_from_aprfile2(errfile, TRUE, pool);
960
961  return svn_client_diff6(diff_options, path1, revision1, path2,
962                          revision2, relative_to_dir, depth,
963                          ignore_ancestry, FALSE /* no_diff_added */,
964                          no_diff_deleted, show_copies_as_adds,
965                          ignore_content_type, FALSE /* ignore_properties */,
966                          FALSE /* properties_only */, use_git_diff_format,
967                          header_encoding,
968                          outstream, errstream, changelists, ctx, pool);
969}
970
971svn_error_t *
972svn_client_diff4(const apr_array_header_t *options,
973                 const char *path1,
974                 const svn_opt_revision_t *revision1,
975                 const char *path2,
976                 const svn_opt_revision_t *revision2,
977                 const char *relative_to_dir,
978                 svn_depth_t depth,
979                 svn_boolean_t ignore_ancestry,
980                 svn_boolean_t no_diff_deleted,
981                 svn_boolean_t ignore_content_type,
982                 const char *header_encoding,
983                 apr_file_t *outfile,
984                 apr_file_t *errfile,
985                 const apr_array_header_t *changelists,
986                 svn_client_ctx_t *ctx,
987                 apr_pool_t *pool)
988{
989  return svn_client_diff5(options, path1, revision1, path2,
990                          revision2, relative_to_dir, depth,
991                          ignore_ancestry, no_diff_deleted, FALSE,
992                          ignore_content_type, FALSE, header_encoding,
993                          outfile, errfile, changelists, ctx, pool);
994}
995
996svn_error_t *
997svn_client_diff3(const apr_array_header_t *options,
998                 const char *path1,
999                 const svn_opt_revision_t *revision1,
1000                 const char *path2,
1001                 const svn_opt_revision_t *revision2,
1002                 svn_boolean_t recurse,
1003                 svn_boolean_t ignore_ancestry,
1004                 svn_boolean_t no_diff_deleted,
1005                 svn_boolean_t ignore_content_type,
1006                 const char *header_encoding,
1007                 apr_file_t *outfile,
1008                 apr_file_t *errfile,
1009                 svn_client_ctx_t *ctx,
1010                 apr_pool_t *pool)
1011{
1012  return svn_client_diff4(options, path1, revision1, path2,
1013                          revision2, NULL,
1014                          SVN_DEPTH_INFINITY_OR_FILES(recurse),
1015                          ignore_ancestry, no_diff_deleted,
1016                          ignore_content_type, header_encoding,
1017                          outfile, errfile, NULL, ctx, pool);
1018}
1019
1020svn_error_t *
1021svn_client_diff2(const apr_array_header_t *options,
1022                 const char *path1,
1023                 const svn_opt_revision_t *revision1,
1024                 const char *path2,
1025                 const svn_opt_revision_t *revision2,
1026                 svn_boolean_t recurse,
1027                 svn_boolean_t ignore_ancestry,
1028                 svn_boolean_t no_diff_deleted,
1029                 svn_boolean_t ignore_content_type,
1030                 apr_file_t *outfile,
1031                 apr_file_t *errfile,
1032                 svn_client_ctx_t *ctx,
1033                 apr_pool_t *pool)
1034{
1035  return svn_client_diff3(options, path1, revision1, path2, revision2,
1036                          recurse, ignore_ancestry, no_diff_deleted,
1037                          ignore_content_type, SVN_APR_LOCALE_CHARSET,
1038                          outfile, errfile, ctx, pool);
1039}
1040
1041svn_error_t *
1042svn_client_diff(const apr_array_header_t *options,
1043                const char *path1,
1044                const svn_opt_revision_t *revision1,
1045                const char *path2,
1046                const svn_opt_revision_t *revision2,
1047                svn_boolean_t recurse,
1048                svn_boolean_t ignore_ancestry,
1049                svn_boolean_t no_diff_deleted,
1050                apr_file_t *outfile,
1051                apr_file_t *errfile,
1052                svn_client_ctx_t *ctx,
1053                apr_pool_t *pool)
1054{
1055  return svn_client_diff2(options, path1, revision1, path2, revision2,
1056                          recurse, ignore_ancestry, no_diff_deleted, FALSE,
1057                          outfile, errfile, ctx, pool);
1058}
1059
1060svn_error_t *
1061svn_client_diff_peg5(const apr_array_header_t *diff_options,
1062                     const char *path,
1063                     const svn_opt_revision_t *peg_revision,
1064                     const svn_opt_revision_t *start_revision,
1065                     const svn_opt_revision_t *end_revision,
1066                     const char *relative_to_dir,
1067                     svn_depth_t depth,
1068                     svn_boolean_t ignore_ancestry,
1069                     svn_boolean_t no_diff_deleted,
1070                     svn_boolean_t show_copies_as_adds,
1071                     svn_boolean_t ignore_content_type,
1072                     svn_boolean_t use_git_diff_format,
1073                     const char *header_encoding,
1074                     apr_file_t *outfile,
1075                     apr_file_t *errfile,
1076                     const apr_array_header_t *changelists,
1077                     svn_client_ctx_t *ctx,
1078                     apr_pool_t *pool)
1079{
1080  svn_stream_t *outstream = svn_stream_from_aprfile2(outfile, TRUE, pool);
1081  svn_stream_t *errstream = svn_stream_from_aprfile2(errfile, TRUE, pool);
1082
1083  return svn_client_diff_peg6(diff_options,
1084                              path,
1085                              peg_revision,
1086                              start_revision,
1087                              end_revision,
1088                              relative_to_dir,
1089                              depth,
1090                              ignore_ancestry,
1091                              FALSE /* no_diff_added */,
1092                              no_diff_deleted,
1093                              show_copies_as_adds,
1094                              ignore_content_type,
1095                              FALSE /* ignore_properties */,
1096                              FALSE /* properties_only */,
1097                              use_git_diff_format,
1098                              header_encoding,
1099                              outstream,
1100                              errstream,
1101                              changelists,
1102                              ctx,
1103                              pool);
1104}
1105
1106svn_error_t *
1107svn_client_diff_peg4(const apr_array_header_t *options,
1108                     const char *path,
1109                     const svn_opt_revision_t *peg_revision,
1110                     const svn_opt_revision_t *start_revision,
1111                     const svn_opt_revision_t *end_revision,
1112                     const char *relative_to_dir,
1113                     svn_depth_t depth,
1114                     svn_boolean_t ignore_ancestry,
1115                     svn_boolean_t no_diff_deleted,
1116                     svn_boolean_t ignore_content_type,
1117                     const char *header_encoding,
1118                     apr_file_t *outfile,
1119                     apr_file_t *errfile,
1120                     const apr_array_header_t *changelists,
1121                     svn_client_ctx_t *ctx,
1122                     apr_pool_t *pool)
1123{
1124  return svn_client_diff_peg5(options,
1125                              path,
1126                              peg_revision,
1127                              start_revision,
1128                              end_revision,
1129                              relative_to_dir,
1130                              depth,
1131                              ignore_ancestry,
1132                              no_diff_deleted,
1133                              FALSE,
1134                              ignore_content_type,
1135                              FALSE,
1136                              header_encoding,
1137                              outfile,
1138                              errfile,
1139                              changelists,
1140                              ctx,
1141                              pool);
1142}
1143
1144svn_error_t *
1145svn_client_diff_peg3(const apr_array_header_t *options,
1146                     const char *path,
1147                     const svn_opt_revision_t *peg_revision,
1148                     const svn_opt_revision_t *start_revision,
1149                     const svn_opt_revision_t *end_revision,
1150                     svn_boolean_t recurse,
1151                     svn_boolean_t ignore_ancestry,
1152                     svn_boolean_t no_diff_deleted,
1153                     svn_boolean_t ignore_content_type,
1154                     const char *header_encoding,
1155                     apr_file_t *outfile,
1156                     apr_file_t *errfile,
1157                     svn_client_ctx_t *ctx,
1158                     apr_pool_t *pool)
1159{
1160  return svn_client_diff_peg4(options,
1161                              path,
1162                              peg_revision,
1163                              start_revision,
1164                              end_revision,
1165                              NULL,
1166                              SVN_DEPTH_INFINITY_OR_FILES(recurse),
1167                              ignore_ancestry,
1168                              no_diff_deleted,
1169                              ignore_content_type,
1170                              header_encoding,
1171                              outfile,
1172                              errfile,
1173                              NULL,
1174                              ctx,
1175                              pool);
1176}
1177
1178svn_error_t *
1179svn_client_diff_peg2(const apr_array_header_t *options,
1180                     const char *path,
1181                     const svn_opt_revision_t *peg_revision,
1182                     const svn_opt_revision_t *start_revision,
1183                     const svn_opt_revision_t *end_revision,
1184                     svn_boolean_t recurse,
1185                     svn_boolean_t ignore_ancestry,
1186                     svn_boolean_t no_diff_deleted,
1187                     svn_boolean_t ignore_content_type,
1188                     apr_file_t *outfile,
1189                     apr_file_t *errfile,
1190                     svn_client_ctx_t *ctx,
1191                     apr_pool_t *pool)
1192{
1193  return svn_client_diff_peg3(options, path, peg_revision, start_revision,
1194                              end_revision,
1195                              SVN_DEPTH_INFINITY_OR_FILES(recurse),
1196                              ignore_ancestry, no_diff_deleted,
1197                              ignore_content_type, SVN_APR_LOCALE_CHARSET,
1198                              outfile, errfile, ctx, pool);
1199}
1200
1201svn_error_t *
1202svn_client_diff_peg(const apr_array_header_t *options,
1203                    const char *path,
1204                    const svn_opt_revision_t *peg_revision,
1205                    const svn_opt_revision_t *start_revision,
1206                    const svn_opt_revision_t *end_revision,
1207                    svn_boolean_t recurse,
1208                    svn_boolean_t ignore_ancestry,
1209                    svn_boolean_t no_diff_deleted,
1210                    apr_file_t *outfile,
1211                    apr_file_t *errfile,
1212                    svn_client_ctx_t *ctx,
1213                    apr_pool_t *pool)
1214{
1215  return svn_client_diff_peg2(options, path, peg_revision,
1216                              start_revision, end_revision, recurse,
1217                              ignore_ancestry, no_diff_deleted, FALSE,
1218                              outfile, errfile, ctx, pool);
1219}
1220
1221svn_error_t *
1222svn_client_diff_summarize(const char *path1,
1223                          const svn_opt_revision_t *revision1,
1224                          const char *path2,
1225                          const svn_opt_revision_t *revision2,
1226                          svn_boolean_t recurse,
1227                          svn_boolean_t ignore_ancestry,
1228                          svn_client_diff_summarize_func_t summarize_func,
1229                          void *summarize_baton,
1230                          svn_client_ctx_t *ctx,
1231                          apr_pool_t *pool)
1232{
1233  return svn_client_diff_summarize2(path1, revision1, path2,
1234                                    revision2,
1235                                    SVN_DEPTH_INFINITY_OR_FILES(recurse),
1236                                    ignore_ancestry, NULL, summarize_func,
1237                                    summarize_baton, ctx, pool);
1238}
1239
1240svn_error_t *
1241svn_client_diff_summarize_peg(const char *path,
1242                              const svn_opt_revision_t *peg_revision,
1243                              const svn_opt_revision_t *start_revision,
1244                              const svn_opt_revision_t *end_revision,
1245                              svn_boolean_t recurse,
1246                              svn_boolean_t ignore_ancestry,
1247                              svn_client_diff_summarize_func_t summarize_func,
1248                              void *summarize_baton,
1249                              svn_client_ctx_t *ctx,
1250                              apr_pool_t *pool)
1251{
1252  return svn_client_diff_summarize_peg2(path, peg_revision,
1253                                        start_revision, end_revision,
1254                                        SVN_DEPTH_INFINITY_OR_FILES(recurse),
1255                                        ignore_ancestry, NULL,
1256                                        summarize_func, summarize_baton,
1257                                        ctx, pool);
1258}
1259
1260/*** From export.c ***/
1261svn_error_t *
1262svn_client_export4(svn_revnum_t *result_rev,
1263                   const char *from_path_or_url,
1264                   const char *to_path,
1265                   const svn_opt_revision_t *peg_revision,
1266                   const svn_opt_revision_t *revision,
1267                   svn_boolean_t overwrite,
1268                   svn_boolean_t ignore_externals,
1269                   svn_depth_t depth,
1270                   const char *native_eol,
1271                   svn_client_ctx_t *ctx,
1272                   apr_pool_t *pool)
1273{
1274  return svn_client_export5(result_rev, from_path_or_url, to_path,
1275                            peg_revision, revision, overwrite, ignore_externals,
1276                            FALSE, depth, native_eol, ctx, pool);
1277}
1278
1279svn_error_t *
1280svn_client_export3(svn_revnum_t *result_rev,
1281                   const char *from_path_or_url,
1282                   const char *to_path,
1283                   const svn_opt_revision_t *peg_revision,
1284                   const svn_opt_revision_t *revision,
1285                   svn_boolean_t overwrite,
1286                   svn_boolean_t ignore_externals,
1287                   svn_boolean_t recurse,
1288                   const char *native_eol,
1289                   svn_client_ctx_t *ctx,
1290                   apr_pool_t *pool)
1291{
1292  return svn_client_export4(result_rev, from_path_or_url, to_path,
1293                            peg_revision, revision, overwrite, ignore_externals,
1294                            SVN_DEPTH_INFINITY_OR_FILES(recurse),
1295                            native_eol, ctx, pool);
1296}
1297
1298svn_error_t *
1299svn_client_export2(svn_revnum_t *result_rev,
1300                   const char *from_path_or_url,
1301                   const char *to_path,
1302                   svn_opt_revision_t *revision,
1303                   svn_boolean_t force,
1304                   const char *native_eol,
1305                   svn_client_ctx_t *ctx,
1306                   apr_pool_t *pool)
1307{
1308  svn_opt_revision_t peg_revision;
1309
1310  peg_revision.kind = svn_opt_revision_unspecified;
1311
1312  return svn_client_export3(result_rev, from_path_or_url, to_path,
1313                            &peg_revision, revision, force, FALSE, TRUE,
1314                            native_eol, ctx, pool);
1315}
1316
1317
1318svn_error_t *
1319svn_client_export(svn_revnum_t *result_rev,
1320                  const char *from_path_or_url,
1321                  const char *to_path,
1322                  svn_opt_revision_t *revision,
1323                  svn_boolean_t force,
1324                  svn_client_ctx_t *ctx,
1325                  apr_pool_t *pool)
1326{
1327  return svn_client_export2(result_rev, from_path_or_url, to_path, revision,
1328                            force, NULL, ctx, pool);
1329}
1330
1331/*** From list.c ***/
1332
1333/* Baton for use with wrap_list_func */
1334struct list_func_wrapper_baton {
1335    void *list_func1_baton;
1336    svn_client_list_func_t list_func1;
1337};
1338
1339/* This implements svn_client_list_func2_t */
1340static svn_error_t *
1341list_func_wrapper(void *baton,
1342                  const char *path,
1343                  const svn_dirent_t *dirent,
1344                  const svn_lock_t *lock,
1345                  const char *abs_path,
1346                  const char *external_parent_url,
1347                  const char *external_target,
1348                  apr_pool_t *scratch_pool)
1349{
1350  struct list_func_wrapper_baton *lfwb = baton;
1351
1352  if (lfwb->list_func1)
1353    return lfwb->list_func1(lfwb->list_func1_baton, path, dirent,
1354                           lock, abs_path, scratch_pool);
1355
1356  return SVN_NO_ERROR;
1357}
1358
1359/* Helper function for svn_client_list2().  It wraps old format baton
1360   and callback function in list_func_wrapper_baton and
1361   returns new baton and callback to use with svn_client_list3(). */
1362static void
1363wrap_list_func(svn_client_list_func2_t *list_func2,
1364               void **list_func2_baton,
1365               svn_client_list_func_t list_func,
1366               void *baton,
1367               apr_pool_t *result_pool)
1368{
1369  struct list_func_wrapper_baton *lfwb = apr_palloc(result_pool,
1370                                                    sizeof(*lfwb));
1371
1372  /* Set the user provided old format callback in the baton. */
1373  lfwb->list_func1_baton = baton;
1374  lfwb->list_func1 = list_func;
1375
1376  *list_func2_baton = lfwb;
1377  *list_func2 = list_func_wrapper;
1378}
1379
1380svn_error_t *
1381svn_client_list2(const char *path_or_url,
1382                 const svn_opt_revision_t *peg_revision,
1383                 const svn_opt_revision_t *revision,
1384                 svn_depth_t depth,
1385                 apr_uint32_t dirent_fields,
1386                 svn_boolean_t fetch_locks,
1387                 svn_client_list_func_t list_func,
1388                 void *baton,
1389                 svn_client_ctx_t *ctx,
1390                 apr_pool_t *pool)
1391{
1392  svn_client_list_func2_t list_func2;
1393  void *list_func2_baton;
1394
1395  wrap_list_func(&list_func2, &list_func2_baton, list_func, baton, pool);
1396
1397  return svn_client_list3(path_or_url, peg_revision, revision, depth,
1398                          dirent_fields, fetch_locks,
1399                          FALSE /* include externals */,
1400                          list_func2, list_func2_baton, ctx, pool);
1401}
1402
1403svn_error_t *
1404svn_client_list(const char *path_or_url,
1405                const svn_opt_revision_t *peg_revision,
1406                const svn_opt_revision_t *revision,
1407                svn_boolean_t recurse,
1408                apr_uint32_t dirent_fields,
1409                svn_boolean_t fetch_locks,
1410                svn_client_list_func_t list_func,
1411                void *baton,
1412                svn_client_ctx_t *ctx,
1413                apr_pool_t *pool)
1414{
1415  return svn_client_list2(path_or_url,
1416                          peg_revision,
1417                          revision,
1418                          SVN_DEPTH_INFINITY_OR_IMMEDIATES(recurse),
1419                          dirent_fields,
1420                          fetch_locks,
1421                          list_func,
1422                          baton,
1423                          ctx,
1424                          pool);
1425}
1426
1427/* Baton used by compatibility wrapper svn_client_ls3. */
1428struct ls_baton {
1429  apr_hash_t *dirents;
1430  apr_hash_t *locks;
1431  apr_pool_t *pool;
1432};
1433
1434/* This implements svn_client_list_func_t. */
1435static svn_error_t *
1436store_dirent(void *baton, const char *path, const svn_dirent_t *dirent,
1437             const svn_lock_t *lock, const char *abs_path, apr_pool_t *pool)
1438{
1439  struct ls_baton *lb = baton;
1440
1441  /* The dirent is allocated in a temporary pool, so duplicate it into the
1442     correct pool.  Note, however, that the locks are stored in the correct
1443     pool already. */
1444  dirent = svn_dirent_dup(dirent, lb->pool);
1445
1446  /* An empty path means we are called for the target of the operation.
1447     For compatibility, we only store the target if it is a file, and we
1448     store it under the basename of the URL.  Note that this makes it
1449     impossible to differentiate between the target being a directory with a
1450     child with the same basename as the target and the target being a file,
1451     but that's how it was implemented. */
1452  if (path[0] == '\0')
1453    {
1454      if (dirent->kind == svn_node_file)
1455        {
1456          const char *base_name = svn_path_basename(abs_path, lb->pool);
1457          svn_hash_sets(lb->dirents, base_name, dirent);
1458          if (lock)
1459            svn_hash_sets(lb->locks, base_name, lock);
1460        }
1461    }
1462  else
1463    {
1464      path = apr_pstrdup(lb->pool, path);
1465      svn_hash_sets(lb->dirents, path, dirent);
1466      if (lock)
1467        svn_hash_sets(lb->locks, path, lock);
1468    }
1469
1470  return SVN_NO_ERROR;
1471}
1472
1473svn_error_t *
1474svn_client_ls3(apr_hash_t **dirents,
1475               apr_hash_t **locks,
1476               const char *path_or_url,
1477               const svn_opt_revision_t *peg_revision,
1478               const svn_opt_revision_t *revision,
1479               svn_boolean_t recurse,
1480               svn_client_ctx_t *ctx,
1481               apr_pool_t *pool)
1482{
1483  struct ls_baton lb;
1484
1485  *dirents = lb.dirents = apr_hash_make(pool);
1486  if (locks)
1487    *locks = lb.locks = apr_hash_make(pool);
1488  lb.pool = pool;
1489
1490  return svn_client_list(path_or_url, peg_revision, revision, recurse,
1491                         SVN_DIRENT_ALL, locks != NULL,
1492                         store_dirent, &lb, ctx, pool);
1493}
1494
1495svn_error_t *
1496svn_client_ls2(apr_hash_t **dirents,
1497               const char *path_or_url,
1498               const svn_opt_revision_t *peg_revision,
1499               const svn_opt_revision_t *revision,
1500               svn_boolean_t recurse,
1501               svn_client_ctx_t *ctx,
1502               apr_pool_t *pool)
1503{
1504
1505  return svn_client_ls3(dirents, NULL, path_or_url, peg_revision,
1506                        revision, recurse, ctx, pool);
1507}
1508
1509
1510svn_error_t *
1511svn_client_ls(apr_hash_t **dirents,
1512              const char *path_or_url,
1513              svn_opt_revision_t *revision,
1514              svn_boolean_t recurse,
1515              svn_client_ctx_t *ctx,
1516              apr_pool_t *pool)
1517{
1518  return svn_client_ls2(dirents, path_or_url, revision,
1519                        revision, recurse, ctx, pool);
1520}
1521
1522/*** From log.c ***/
1523
1524svn_error_t *
1525svn_client_log4(const apr_array_header_t *targets,
1526                const svn_opt_revision_t *peg_revision,
1527                const svn_opt_revision_t *start,
1528                const svn_opt_revision_t *end,
1529                int limit,
1530                svn_boolean_t discover_changed_paths,
1531                svn_boolean_t strict_node_history,
1532                svn_boolean_t include_merged_revisions,
1533                const apr_array_header_t *revprops,
1534                svn_log_entry_receiver_t receiver,
1535                void *receiver_baton,
1536                svn_client_ctx_t *ctx,
1537                apr_pool_t *pool)
1538{
1539  apr_array_header_t *revision_ranges;
1540
1541  revision_ranges = apr_array_make(pool, 1,
1542                                   sizeof(svn_opt_revision_range_t *));
1543  APR_ARRAY_PUSH(revision_ranges, svn_opt_revision_range_t *)
1544    = svn_opt__revision_range_create(start, end, pool);
1545
1546  return svn_client_log5(targets, peg_revision, revision_ranges, limit,
1547                         discover_changed_paths, strict_node_history,
1548                         include_merged_revisions, revprops, receiver,
1549                         receiver_baton, ctx, pool);
1550}
1551
1552
1553svn_error_t *
1554svn_client_log3(const apr_array_header_t *targets,
1555                const svn_opt_revision_t *peg_revision,
1556                const svn_opt_revision_t *start,
1557                const svn_opt_revision_t *end,
1558                int limit,
1559                svn_boolean_t discover_changed_paths,
1560                svn_boolean_t strict_node_history,
1561                svn_log_message_receiver_t receiver,
1562                void *receiver_baton,
1563                svn_client_ctx_t *ctx,
1564                apr_pool_t *pool)
1565{
1566  svn_log_entry_receiver_t receiver2;
1567  void *receiver2_baton;
1568
1569  svn_compat_wrap_log_receiver(&receiver2, &receiver2_baton,
1570                               receiver, receiver_baton,
1571                               pool);
1572
1573  return svn_client_log4(targets, peg_revision, start, end, limit,
1574                         discover_changed_paths, strict_node_history, FALSE,
1575                         svn_compat_log_revprops_in(pool),
1576                         receiver2, receiver2_baton, ctx, pool);
1577}
1578
1579svn_error_t *
1580svn_client_log2(const apr_array_header_t *targets,
1581                const svn_opt_revision_t *start,
1582                const svn_opt_revision_t *end,
1583                int limit,
1584                svn_boolean_t discover_changed_paths,
1585                svn_boolean_t strict_node_history,
1586                svn_log_message_receiver_t receiver,
1587                void *receiver_baton,
1588                svn_client_ctx_t *ctx,
1589                apr_pool_t *pool)
1590{
1591  svn_opt_revision_t peg_revision;
1592  peg_revision.kind = svn_opt_revision_unspecified;
1593  return svn_client_log3(targets, &peg_revision, start, end, limit,
1594                         discover_changed_paths, strict_node_history,
1595                         receiver, receiver_baton, ctx, pool);
1596}
1597
1598svn_error_t *
1599svn_client_log(const apr_array_header_t *targets,
1600               const svn_opt_revision_t *start,
1601               const svn_opt_revision_t *end,
1602               svn_boolean_t discover_changed_paths,
1603               svn_boolean_t strict_node_history,
1604               svn_log_message_receiver_t receiver,
1605               void *receiver_baton,
1606               svn_client_ctx_t *ctx,
1607               apr_pool_t *pool)
1608{
1609  svn_error_t *err = SVN_NO_ERROR;
1610
1611  err = svn_client_log2(targets, start, end, 0, discover_changed_paths,
1612                        strict_node_history, receiver, receiver_baton, ctx,
1613                        pool);
1614
1615  /* Special case: If there have been no commits, we'll get an error
1616   * for requesting log of a revision higher than 0.  But the
1617   * default behavior of "svn log" is to give revisions HEAD through
1618   * 1, on the assumption that HEAD >= 1.
1619   *
1620   * So if we got that error for that reason, and it looks like the
1621   * user was just depending on the defaults (rather than explicitly
1622   * requesting the log for revision 1), then we don't error.  Instead
1623   * we just invoke the receiver manually on a hand-constructed log
1624   * message for revision 0.
1625   *
1626   * See also http://subversion.tigris.org/issues/show_bug.cgi?id=692.
1627   */
1628  if (err && (err->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
1629      && (start->kind == svn_opt_revision_head)
1630      && ((end->kind == svn_opt_revision_number)
1631          && (end->value.number == 1)))
1632    {
1633
1634      /* We don't need to check if HEAD is 0, because that must be the case,
1635       * by logical deduction: The revision range specified is HEAD:1.
1636       * HEAD cannot not exist, so the revision to which "no such revision"
1637       * applies is 1. If revision 1 does not exist, then HEAD is 0.
1638       * Hence, we deduce the repository is empty without needing access
1639       * to further information. */
1640
1641      svn_error_clear(err);
1642      err = SVN_NO_ERROR;
1643
1644      /* Log receivers are free to handle revision 0 specially... But
1645         just in case some don't, we make up a message here. */
1646      SVN_ERR(receiver(receiver_baton,
1647                       NULL, 0, "", "", _("No commits in repository"),
1648                       pool));
1649    }
1650
1651  return svn_error_trace(err);
1652}
1653
1654/*** From merge.c ***/
1655
1656svn_error_t *
1657svn_client_merge4(const char *source1,
1658                  const svn_opt_revision_t *revision1,
1659                  const char *source2,
1660                  const svn_opt_revision_t *revision2,
1661                  const char *target_wcpath,
1662                  svn_depth_t depth,
1663                  svn_boolean_t ignore_ancestry,
1664                  svn_boolean_t force_delete,
1665                  svn_boolean_t record_only,
1666                  svn_boolean_t dry_run,
1667                  svn_boolean_t allow_mixed_rev,
1668                  const apr_array_header_t *merge_options,
1669                  svn_client_ctx_t *ctx,
1670                  apr_pool_t *pool)
1671{
1672  SVN_ERR(svn_client_merge5(source1, revision1,
1673                            source2, revision2,
1674                            target_wcpath,
1675                            depth,
1676                            ignore_ancestry /*ignore_mergeinfo*/,
1677                            ignore_ancestry /*diff_ignore_ancestry*/,
1678                            force_delete, record_only,
1679                            dry_run, allow_mixed_rev,
1680                            merge_options, ctx, pool));
1681  return SVN_NO_ERROR;
1682}
1683
1684svn_error_t *
1685svn_client_merge3(const char *source1,
1686                  const svn_opt_revision_t *revision1,
1687                  const char *source2,
1688                  const svn_opt_revision_t *revision2,
1689                  const char *target_wcpath,
1690                  svn_depth_t depth,
1691                  svn_boolean_t ignore_ancestry,
1692                  svn_boolean_t force,
1693                  svn_boolean_t record_only,
1694                  svn_boolean_t dry_run,
1695                  const apr_array_header_t *merge_options,
1696                  svn_client_ctx_t *ctx,
1697                  apr_pool_t *pool)
1698{
1699  return svn_client_merge4(source1, revision1, source2, revision2,
1700                           target_wcpath, depth, ignore_ancestry, force,
1701                           record_only, dry_run, TRUE, merge_options,
1702                           ctx, pool);
1703}
1704
1705svn_error_t *
1706svn_client_merge2(const char *source1,
1707                  const svn_opt_revision_t *revision1,
1708                  const char *source2,
1709                  const svn_opt_revision_t *revision2,
1710                  const char *target_wcpath,
1711                  svn_boolean_t recurse,
1712                  svn_boolean_t ignore_ancestry,
1713                  svn_boolean_t force,
1714                  svn_boolean_t dry_run,
1715                  const apr_array_header_t *merge_options,
1716                  svn_client_ctx_t *ctx,
1717                  apr_pool_t *pool)
1718{
1719  return svn_client_merge3(source1, revision1, source2, revision2,
1720                           target_wcpath,
1721                           SVN_DEPTH_INFINITY_OR_FILES(recurse),
1722                           ignore_ancestry, force, FALSE, dry_run,
1723                           merge_options, ctx, pool);
1724}
1725
1726svn_error_t *
1727svn_client_merge(const char *source1,
1728                 const svn_opt_revision_t *revision1,
1729                 const char *source2,
1730                 const svn_opt_revision_t *revision2,
1731                 const char *target_wcpath,
1732                 svn_boolean_t recurse,
1733                 svn_boolean_t ignore_ancestry,
1734                 svn_boolean_t force,
1735                 svn_boolean_t dry_run,
1736                 svn_client_ctx_t *ctx,
1737                 apr_pool_t *pool)
1738{
1739  return svn_client_merge2(source1, revision1, source2, revision2,
1740                           target_wcpath, recurse, ignore_ancestry, force,
1741                           dry_run, NULL, ctx, pool);
1742}
1743
1744svn_error_t *
1745svn_client_merge_peg4(const char *source_path_or_url,
1746                      const apr_array_header_t *ranges_to_merge,
1747                      const svn_opt_revision_t *source_peg_revision,
1748                      const char *target_wcpath,
1749                      svn_depth_t depth,
1750                      svn_boolean_t ignore_ancestry,
1751                      svn_boolean_t force_delete,
1752                      svn_boolean_t record_only,
1753                      svn_boolean_t dry_run,
1754                      svn_boolean_t allow_mixed_rev,
1755                      const apr_array_header_t *merge_options,
1756                      svn_client_ctx_t *ctx,
1757                      apr_pool_t *pool)
1758{
1759  SVN_ERR(svn_client_merge_peg5(source_path_or_url,
1760                                ranges_to_merge,
1761                                source_peg_revision,
1762                                target_wcpath,
1763                                depth,
1764                                ignore_ancestry /*ignore_mergeinfo*/,
1765                                ignore_ancestry /*diff_ignore_ancestry*/,
1766                                force_delete, record_only,
1767                                dry_run, allow_mixed_rev,
1768                                merge_options, ctx, pool));
1769  return SVN_NO_ERROR;
1770}
1771
1772svn_error_t *
1773svn_client_merge_peg3(const char *source,
1774                      const apr_array_header_t *ranges_to_merge,
1775                      const svn_opt_revision_t *peg_revision,
1776                      const char *target_wcpath,
1777                      svn_depth_t depth,
1778                      svn_boolean_t ignore_ancestry,
1779                      svn_boolean_t force,
1780                      svn_boolean_t record_only,
1781                      svn_boolean_t dry_run,
1782                      const apr_array_header_t *merge_options,
1783                      svn_client_ctx_t *ctx,
1784                      apr_pool_t *pool)
1785{
1786  return svn_client_merge_peg4(source, ranges_to_merge, peg_revision,
1787                               target_wcpath, depth, ignore_ancestry, force,
1788                               record_only, dry_run, TRUE, merge_options,
1789                               ctx, pool);
1790}
1791
1792svn_error_t *
1793svn_client_merge_peg2(const char *source,
1794                      const svn_opt_revision_t *revision1,
1795                      const svn_opt_revision_t *revision2,
1796                      const svn_opt_revision_t *peg_revision,
1797                      const char *target_wcpath,
1798                      svn_boolean_t recurse,
1799                      svn_boolean_t ignore_ancestry,
1800                      svn_boolean_t force,
1801                      svn_boolean_t dry_run,
1802                      const apr_array_header_t *merge_options,
1803                      svn_client_ctx_t *ctx,
1804                      apr_pool_t *pool)
1805{
1806  apr_array_header_t *ranges_to_merge =
1807    apr_array_make(pool, 1, sizeof(svn_opt_revision_range_t *));
1808
1809  APR_ARRAY_PUSH(ranges_to_merge, svn_opt_revision_range_t *)
1810    = svn_opt__revision_range_create(revision1, revision2, pool);
1811  return svn_client_merge_peg3(source, ranges_to_merge,
1812                               peg_revision,
1813                               target_wcpath,
1814                               SVN_DEPTH_INFINITY_OR_FILES(recurse),
1815                               ignore_ancestry, force, FALSE, dry_run,
1816                               merge_options, ctx, pool);
1817}
1818
1819svn_error_t *
1820svn_client_merge_peg(const char *source,
1821                     const svn_opt_revision_t *revision1,
1822                     const svn_opt_revision_t *revision2,
1823                     const svn_opt_revision_t *peg_revision,
1824                     const char *target_wcpath,
1825                     svn_boolean_t recurse,
1826                     svn_boolean_t ignore_ancestry,
1827                     svn_boolean_t force,
1828                     svn_boolean_t dry_run,
1829                     svn_client_ctx_t *ctx,
1830                     apr_pool_t *pool)
1831{
1832  return svn_client_merge_peg2(source, revision1, revision2, peg_revision,
1833                               target_wcpath, recurse, ignore_ancestry, force,
1834                               dry_run, NULL, ctx, pool);
1835}
1836
1837/*** From prop_commands.c ***/
1838svn_error_t *
1839svn_client_propset3(svn_commit_info_t **commit_info_p,
1840                    const char *propname,
1841                    const svn_string_t *propval,
1842                    const char *target,
1843                    svn_depth_t depth,
1844                    svn_boolean_t skip_checks,
1845                    svn_revnum_t base_revision_for_url,
1846                    const apr_array_header_t *changelists,
1847                    const apr_hash_t *revprop_table,
1848                    svn_client_ctx_t *ctx,
1849                    apr_pool_t *pool)
1850{
1851  if (svn_path_is_url(target))
1852    {
1853      struct capture_baton_t cb;
1854
1855      cb.info = commit_info_p;
1856      cb.pool = pool;
1857
1858      SVN_ERR(svn_client_propset_remote(propname, propval, target, skip_checks,
1859                                        base_revision_for_url, revprop_table,
1860                                        capture_commit_info, &cb, ctx, pool));
1861    }
1862  else
1863    {
1864      apr_array_header_t *targets = apr_array_make(pool, 1,
1865                                                   sizeof(const char *));
1866
1867      APR_ARRAY_PUSH(targets, const char *) = target;
1868      SVN_ERR(svn_client_propset_local(propname, propval, targets, depth,
1869                                       skip_checks, changelists, ctx, pool));
1870    }
1871
1872  return SVN_NO_ERROR;
1873}
1874
1875svn_error_t *
1876svn_client_propset2(const char *propname,
1877                    const svn_string_t *propval,
1878                    const char *target,
1879                    svn_boolean_t recurse,
1880                    svn_boolean_t skip_checks,
1881                    svn_client_ctx_t *ctx,
1882                    apr_pool_t *pool)
1883{
1884  return svn_client_propset3(NULL, propname, propval, target,
1885                             SVN_DEPTH_INFINITY_OR_EMPTY(recurse),
1886                             skip_checks, SVN_INVALID_REVNUM,
1887                             NULL, NULL, ctx, pool);
1888}
1889
1890
1891svn_error_t *
1892svn_client_propset(const char *propname,
1893                   const svn_string_t *propval,
1894                   const char *target,
1895                   svn_boolean_t recurse,
1896                   apr_pool_t *pool)
1897{
1898  svn_client_ctx_t *ctx;
1899
1900  SVN_ERR(svn_client_create_context(&ctx, pool));
1901
1902  return svn_client_propset2(propname, propval, target, recurse, FALSE,
1903                             ctx, pool);
1904}
1905
1906svn_error_t *
1907svn_client_revprop_set(const char *propname,
1908                       const svn_string_t *propval,
1909                       const char *URL,
1910                       const svn_opt_revision_t *revision,
1911                       svn_revnum_t *set_rev,
1912                       svn_boolean_t force,
1913                       svn_client_ctx_t *ctx,
1914                       apr_pool_t *pool)
1915{
1916  return svn_client_revprop_set2(propname, propval, NULL, URL,
1917                                 revision, set_rev, force, ctx, pool);
1918
1919}
1920
1921svn_error_t *
1922svn_client_propget4(apr_hash_t **props,
1923                    const char *propname,
1924                    const char *target,
1925                    const svn_opt_revision_t *peg_revision,
1926                    const svn_opt_revision_t *revision,
1927                    svn_revnum_t *actual_revnum,
1928                    svn_depth_t depth,
1929                    const apr_array_header_t *changelists,
1930                    svn_client_ctx_t *ctx,
1931                    apr_pool_t *result_pool,
1932                    apr_pool_t *scratch_pool)
1933{
1934  return svn_error_trace(svn_client_propget5(props, NULL, propname, target,
1935                                             peg_revision, revision,
1936                                             actual_revnum, depth,
1937                                             changelists, ctx,
1938                                             result_pool, scratch_pool));
1939}
1940
1941svn_error_t *
1942svn_client_propget3(apr_hash_t **props,
1943                    const char *propname,
1944                    const char *path_or_url,
1945                    const svn_opt_revision_t *peg_revision,
1946                    const svn_opt_revision_t *revision,
1947                    svn_revnum_t *actual_revnum,
1948                    svn_depth_t depth,
1949                    const apr_array_header_t *changelists,
1950                    svn_client_ctx_t *ctx,
1951                    apr_pool_t *pool)
1952{
1953  const char *target;
1954  apr_hash_t *temp_props;
1955  svn_error_t *err;
1956
1957  if (svn_path_is_url(path_or_url))
1958    target = path_or_url;
1959  else
1960    SVN_ERR(svn_dirent_get_absolute(&target, path_or_url, pool));
1961
1962  err = svn_client_propget4(&temp_props, propname, target,
1963                            peg_revision, revision, actual_revnum,
1964                            depth, changelists, ctx, pool, pool);
1965
1966  if (err && err->apr_err == SVN_ERR_UNVERSIONED_RESOURCE)
1967    {
1968      err->apr_err = SVN_ERR_ENTRY_NOT_FOUND;
1969      return svn_error_trace(err);
1970    }
1971  else
1972    SVN_ERR(err);
1973
1974  if (actual_revnum
1975        && !svn_path_is_url(path_or_url)
1976        && !SVN_IS_VALID_REVNUM(*actual_revnum))
1977    {
1978      /* Get the actual_revnum; added nodes have no revision yet, and old
1979       * callers expected the mock-up revision of 0. */
1980      svn_boolean_t added;
1981
1982      SVN_ERR(svn_wc__node_is_added(&added, ctx->wc_ctx, target, pool));
1983      if (added)
1984        *actual_revnum = 0;
1985    }
1986
1987  /* We may need to fix up our hash keys for legacy callers. */
1988  if (!svn_path_is_url(path_or_url) && strcmp(target, path_or_url) != 0)
1989    {
1990      apr_hash_index_t *hi;
1991
1992      *props = apr_hash_make(pool);
1993      for (hi = apr_hash_first(pool, temp_props); hi;
1994            hi = apr_hash_next(hi))
1995        {
1996          const char *abspath = apr_hash_this_key(hi);
1997          svn_string_t *value = apr_hash_this_val(hi);
1998          const char *relpath = svn_dirent_join(path_or_url,
1999                                     svn_dirent_skip_ancestor(target, abspath),
2000                                     pool);
2001
2002          svn_hash_sets(*props, relpath, value);
2003        }
2004    }
2005  else
2006    *props = temp_props;
2007
2008  return SVN_NO_ERROR;
2009}
2010
2011svn_error_t *
2012svn_client_propget2(apr_hash_t **props,
2013                    const char *propname,
2014                    const char *target,
2015                    const svn_opt_revision_t *peg_revision,
2016                    const svn_opt_revision_t *revision,
2017                    svn_boolean_t recurse,
2018                    svn_client_ctx_t *ctx,
2019                    apr_pool_t *pool)
2020{
2021  return svn_client_propget3(props,
2022                             propname,
2023                             target,
2024                             peg_revision,
2025                             revision,
2026                             NULL,
2027                             SVN_DEPTH_INFINITY_OR_EMPTY(recurse),
2028                             NULL,
2029                             ctx,
2030                             pool);
2031}
2032
2033svn_error_t *
2034svn_client_propget(apr_hash_t **props,
2035                   const char *propname,
2036                   const char *target,
2037                   const svn_opt_revision_t *revision,
2038                   svn_boolean_t recurse,
2039                   svn_client_ctx_t *ctx,
2040                   apr_pool_t *pool)
2041{
2042  return svn_client_propget2(props, propname, target, revision, revision,
2043                             recurse, ctx, pool);
2044}
2045
2046
2047/* Duplicate a HASH containing (char * -> svn_string_t *) key/value
2048   pairs using POOL. */
2049static apr_hash_t *
2050string_hash_dup(apr_hash_t *hash, apr_pool_t *pool)
2051{
2052  apr_hash_index_t *hi;
2053  apr_hash_t *new_hash = apr_hash_make(pool);
2054
2055  for (hi = apr_hash_first(pool, hash); hi; hi = apr_hash_next(hi))
2056    {
2057      const char *key = apr_pstrdup(pool, apr_hash_this_key(hi));
2058      apr_ssize_t klen = apr_hash_this_key_len(hi);
2059      svn_string_t *val = svn_string_dup(apr_hash_this_val(hi), pool);
2060
2061      apr_hash_set(new_hash, key, klen, val);
2062    }
2063  return new_hash;
2064}
2065
2066svn_client_proplist_item_t *
2067svn_client_proplist_item_dup(const svn_client_proplist_item_t *item,
2068                             apr_pool_t * pool)
2069{
2070  svn_client_proplist_item_t *new_item = apr_pcalloc(pool, sizeof(*new_item));
2071
2072  if (item->node_name)
2073    new_item->node_name = svn_stringbuf_dup(item->node_name, pool);
2074
2075  if (item->prop_hash)
2076    new_item->prop_hash = string_hash_dup(item->prop_hash, pool);
2077
2078  return new_item;
2079}
2080
2081/* Baton for use with wrap_proplist_receiver */
2082struct proplist_receiver_wrapper_baton {
2083  void *baton;
2084  svn_proplist_receiver_t receiver;
2085};
2086
2087/* This implements svn_client_proplist_receiver2_t */
2088static svn_error_t *
2089proplist_wrapper_receiver(void *baton,
2090                          const char *path,
2091                          apr_hash_t *prop_hash,
2092                          apr_array_header_t *inherited_props,
2093                          apr_pool_t *pool)
2094{
2095  struct proplist_receiver_wrapper_baton *plrwb = baton;
2096
2097  if (plrwb->receiver)
2098    return plrwb->receiver(plrwb->baton, path, prop_hash, pool);
2099
2100  return SVN_NO_ERROR;
2101}
2102
2103static void
2104wrap_proplist_receiver(svn_proplist_receiver2_t *receiver2,
2105                       void **receiver2_baton,
2106                       svn_proplist_receiver_t receiver,
2107                       void *receiver_baton,
2108                       apr_pool_t *pool)
2109{
2110  struct proplist_receiver_wrapper_baton *plrwb = apr_palloc(pool,
2111                                                             sizeof(*plrwb));
2112
2113  /* Set the user provided old format callback in the baton. */
2114  plrwb->baton = receiver_baton;
2115  plrwb->receiver = receiver;
2116
2117  *receiver2_baton = plrwb;
2118  *receiver2 = proplist_wrapper_receiver;
2119}
2120
2121svn_error_t *
2122svn_client_proplist3(const char *target,
2123                     const svn_opt_revision_t *peg_revision,
2124                     const svn_opt_revision_t *revision,
2125                     svn_depth_t depth,
2126                     const apr_array_header_t *changelists,
2127                     svn_proplist_receiver_t receiver,
2128                     void *receiver_baton,
2129                     svn_client_ctx_t *ctx,
2130                     apr_pool_t *pool)
2131{
2132
2133  svn_proplist_receiver2_t receiver2;
2134  void *receiver2_baton;
2135
2136  wrap_proplist_receiver(&receiver2, &receiver2_baton, receiver, receiver_baton,
2137                         pool);
2138
2139  return svn_error_trace(svn_client_proplist4(target, peg_revision, revision,
2140                                              depth, changelists, FALSE,
2141                                              receiver2, receiver2_baton,
2142                                              ctx, pool));
2143}
2144
2145/* Receiver baton used by proplist2() */
2146struct proplist_receiver_baton {
2147  apr_array_header_t *props;
2148  apr_pool_t *pool;
2149};
2150
2151/* Receiver function used by proplist2(). */
2152static svn_error_t *
2153proplist_receiver_cb(void *baton,
2154                     const char *path,
2155                     apr_hash_t *prop_hash,
2156                     apr_pool_t *pool)
2157{
2158  struct proplist_receiver_baton *pl_baton =
2159    (struct proplist_receiver_baton *) baton;
2160  svn_client_proplist_item_t *tmp_item = apr_palloc(pool, sizeof(*tmp_item));
2161  svn_client_proplist_item_t *item;
2162
2163  /* Because the pool passed to the receiver function is likely to be a
2164     temporary pool of some kind, we need to make copies of *path and
2165     *prop_hash in the pool provided by the baton. */
2166  tmp_item->node_name = svn_stringbuf_create(path, pl_baton->pool);
2167  tmp_item->prop_hash = prop_hash;
2168
2169  item = svn_client_proplist_item_dup(tmp_item, pl_baton->pool);
2170
2171  APR_ARRAY_PUSH(pl_baton->props, const svn_client_proplist_item_t *) = item;
2172
2173  return SVN_NO_ERROR;
2174}
2175
2176svn_error_t *
2177svn_client_proplist2(apr_array_header_t **props,
2178                     const char *target,
2179                     const svn_opt_revision_t *peg_revision,
2180                     const svn_opt_revision_t *revision,
2181                     svn_boolean_t recurse,
2182                     svn_client_ctx_t *ctx,
2183                     apr_pool_t *pool)
2184{
2185  struct proplist_receiver_baton pl_baton;
2186
2187  *props = apr_array_make(pool, 5, sizeof(svn_client_proplist_item_t *));
2188  pl_baton.props = *props;
2189  pl_baton.pool = pool;
2190
2191  return svn_client_proplist3(target, peg_revision, revision,
2192                              SVN_DEPTH_INFINITY_OR_EMPTY(recurse), NULL,
2193                              proplist_receiver_cb, &pl_baton, ctx, pool);
2194}
2195
2196
2197svn_error_t *
2198svn_client_proplist(apr_array_header_t **props,
2199                    const char *target,
2200                    const svn_opt_revision_t *revision,
2201                    svn_boolean_t recurse,
2202                    svn_client_ctx_t *ctx,
2203                    apr_pool_t *pool)
2204{
2205  return svn_client_proplist2(props, target, revision, revision,
2206                              recurse, ctx, pool);
2207}
2208
2209/*** From status.c ***/
2210
2211svn_error_t *
2212svn_client_status5(svn_revnum_t *result_rev,
2213                   svn_client_ctx_t *ctx,
2214                   const char *path,
2215                   const svn_opt_revision_t *revision,
2216                   svn_depth_t depth,
2217                   svn_boolean_t get_all,
2218                   svn_boolean_t update,
2219                   svn_boolean_t no_ignore,
2220                   svn_boolean_t ignore_externals,
2221                   svn_boolean_t depth_as_sticky,
2222                   const apr_array_header_t *changelists,
2223                   svn_client_status_func_t status_func,
2224                   void *status_baton,
2225                   apr_pool_t *scratch_pool)
2226{
2227  return svn_client_status6(result_rev, ctx, path, revision, depth,
2228                            get_all, update, TRUE, no_ignore,
2229                            ignore_externals, depth_as_sticky, changelists,
2230                            status_func, status_baton, scratch_pool);
2231}
2232
2233struct status4_wrapper_baton
2234{
2235  svn_wc_context_t *wc_ctx;
2236  svn_wc_status_func3_t old_func;
2237  void *old_baton;
2238};
2239
2240/* Implements svn_client_status_func_t */
2241static svn_error_t *
2242status4_wrapper_func(void *baton,
2243                     const char *path,
2244                     const svn_client_status_t *status,
2245                     apr_pool_t *scratch_pool)
2246{
2247  struct status4_wrapper_baton *swb = baton;
2248  svn_wc_status2_t *dup;
2249  const char *local_abspath;
2250  const svn_wc_status3_t *wc_status = status->backwards_compatibility_baton;
2251
2252  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
2253  SVN_ERR(svn_wc__status2_from_3(&dup, wc_status, swb->wc_ctx,
2254                                 local_abspath, scratch_pool,
2255                                 scratch_pool));
2256
2257  return (*swb->old_func)(swb->old_baton, path, dup, scratch_pool);
2258}
2259
2260svn_error_t *
2261svn_client_status4(svn_revnum_t *result_rev,
2262                   const char *path,
2263                   const svn_opt_revision_t *revision,
2264                   svn_wc_status_func3_t status_func,
2265                   void *status_baton,
2266                   svn_depth_t depth,
2267                   svn_boolean_t get_all,
2268                   svn_boolean_t update,
2269                   svn_boolean_t no_ignore,
2270                   svn_boolean_t ignore_externals,
2271                   const apr_array_header_t *changelists,
2272                   svn_client_ctx_t *ctx,
2273                   apr_pool_t *pool)
2274{
2275  struct status4_wrapper_baton swb;
2276
2277  swb.wc_ctx = ctx->wc_ctx;
2278  swb.old_func = status_func;
2279  swb.old_baton = status_baton;
2280
2281  return svn_client_status5(result_rev, ctx, path, revision, depth, get_all,
2282                            update, no_ignore, ignore_externals, TRUE,
2283                            changelists, status4_wrapper_func, &swb, pool);
2284}
2285
2286struct status3_wrapper_baton
2287{
2288  svn_wc_status_func2_t old_func;
2289  void *old_baton;
2290};
2291
2292static svn_error_t *
2293status3_wrapper_func(void *baton,
2294                     const char *path,
2295                     svn_wc_status2_t *status,
2296                     apr_pool_t *pool)
2297{
2298  struct status3_wrapper_baton *swb = baton;
2299
2300  swb->old_func(swb->old_baton, path, status);
2301  return SVN_NO_ERROR;
2302}
2303
2304svn_error_t *
2305svn_client_status3(svn_revnum_t *result_rev,
2306                   const char *path,
2307                   const svn_opt_revision_t *revision,
2308                   svn_wc_status_func2_t status_func,
2309                   void *status_baton,
2310                   svn_depth_t depth,
2311                   svn_boolean_t get_all,
2312                   svn_boolean_t update,
2313                   svn_boolean_t no_ignore,
2314                   svn_boolean_t ignore_externals,
2315                   const apr_array_header_t *changelists,
2316                   svn_client_ctx_t *ctx,
2317                   apr_pool_t *pool)
2318{
2319  struct status3_wrapper_baton swb = { 0 };
2320  swb.old_func = status_func;
2321  swb.old_baton = status_baton;
2322  return svn_client_status4(result_rev, path, revision, status3_wrapper_func,
2323                            &swb, depth, get_all, update, no_ignore,
2324                            ignore_externals, changelists, ctx, pool);
2325}
2326
2327svn_error_t *
2328svn_client_status2(svn_revnum_t *result_rev,
2329                   const char *path,
2330                   const svn_opt_revision_t *revision,
2331                   svn_wc_status_func2_t status_func,
2332                   void *status_baton,
2333                   svn_boolean_t recurse,
2334                   svn_boolean_t get_all,
2335                   svn_boolean_t update,
2336                   svn_boolean_t no_ignore,
2337                   svn_boolean_t ignore_externals,
2338                   svn_client_ctx_t *ctx,
2339                   apr_pool_t *pool)
2340{
2341  return svn_client_status3(result_rev, path, revision,
2342                            status_func, status_baton,
2343                            SVN_DEPTH_INFINITY_OR_IMMEDIATES(recurse),
2344                            get_all, update, no_ignore, ignore_externals, NULL,
2345                            ctx, pool);
2346}
2347
2348
2349/* Baton for old_status_func_cb; does what you think it does. */
2350struct old_status_func_cb_baton
2351{
2352  svn_wc_status_func_t original_func;
2353  void *original_baton;
2354};
2355
2356/* Help svn_client_status() accept an old-style status func and baton,
2357   by wrapping them before passing along to svn_client_status2().
2358
2359   This implements the 'svn_wc_status_func2_t' function type. */
2360static void old_status_func_cb(void *baton,
2361                               const char *path,
2362                               svn_wc_status2_t *status)
2363{
2364  struct old_status_func_cb_baton *b = baton;
2365  svn_wc_status_t *stat = (svn_wc_status_t *) status;
2366
2367  b->original_func(b->original_baton, path, stat);
2368}
2369
2370
2371svn_error_t *
2372svn_client_status(svn_revnum_t *result_rev,
2373                  const char *path,
2374                  svn_opt_revision_t *revision,
2375                  svn_wc_status_func_t status_func,
2376                  void *status_baton,
2377                  svn_boolean_t recurse,
2378                  svn_boolean_t get_all,
2379                  svn_boolean_t update,
2380                  svn_boolean_t no_ignore,
2381                  svn_client_ctx_t *ctx,
2382                  apr_pool_t *pool)
2383{
2384  struct old_status_func_cb_baton *b = apr_pcalloc(pool, sizeof(*b));
2385  b->original_func = status_func;
2386  b->original_baton = status_baton;
2387
2388  return svn_client_status2(result_rev, path, revision,
2389                            old_status_func_cb, b,
2390                            recurse, get_all, update, no_ignore, FALSE,
2391                            ctx, pool);
2392}
2393
2394/*** From update.c ***/
2395svn_error_t *
2396svn_client_update3(apr_array_header_t **result_revs,
2397                   const apr_array_header_t *paths,
2398                   const svn_opt_revision_t *revision,
2399                   svn_depth_t depth,
2400                   svn_boolean_t depth_is_sticky,
2401                   svn_boolean_t ignore_externals,
2402                   svn_boolean_t allow_unver_obstructions,
2403                   svn_client_ctx_t *ctx,
2404                   apr_pool_t *pool)
2405{
2406  return svn_client_update4(result_revs, paths, revision,
2407                            depth, depth_is_sticky, ignore_externals,
2408                            allow_unver_obstructions, TRUE, FALSE,
2409                            ctx, pool);
2410}
2411
2412svn_error_t *
2413svn_client_update2(apr_array_header_t **result_revs,
2414                   const apr_array_header_t *paths,
2415                   const svn_opt_revision_t *revision,
2416                   svn_boolean_t recurse,
2417                   svn_boolean_t ignore_externals,
2418                   svn_client_ctx_t *ctx,
2419                   apr_pool_t *pool)
2420{
2421  return svn_client_update3(result_revs, paths, revision,
2422                            SVN_DEPTH_INFINITY_OR_FILES(recurse), FALSE,
2423                            ignore_externals, FALSE, ctx, pool);
2424}
2425
2426svn_error_t *
2427svn_client_update(svn_revnum_t *result_rev,
2428                  const char *path,
2429                  const svn_opt_revision_t *revision,
2430                  svn_boolean_t recurse,
2431                  svn_client_ctx_t *ctx,
2432                  apr_pool_t *pool)
2433{
2434  apr_array_header_t *paths = apr_array_make(pool, 1, sizeof(const char *));
2435  apr_array_header_t *result_revs;
2436
2437  APR_ARRAY_PUSH(paths, const char *) = path;
2438
2439  SVN_ERR(svn_client_update2(&result_revs, paths, revision, recurse, FALSE,
2440                             ctx, pool));
2441
2442  *result_rev = APR_ARRAY_IDX(result_revs, 0, svn_revnum_t);
2443
2444  return SVN_NO_ERROR;
2445}
2446
2447/*** From switch.c ***/
2448svn_error_t *
2449svn_client_switch2(svn_revnum_t *result_rev,
2450                   const char *path,
2451                   const char *switch_url,
2452                   const svn_opt_revision_t *peg_revision,
2453                   const svn_opt_revision_t *revision,
2454                   svn_depth_t depth,
2455                   svn_boolean_t depth_is_sticky,
2456                   svn_boolean_t ignore_externals,
2457                   svn_boolean_t allow_unver_obstructions,
2458                   svn_client_ctx_t *ctx,
2459                   apr_pool_t *pool)
2460{
2461  return svn_client_switch3(result_rev, path, switch_url, peg_revision,
2462                            revision, depth, depth_is_sticky, ignore_externals,
2463                            allow_unver_obstructions,
2464                            TRUE /* ignore_ancestry */,
2465                            ctx, pool);
2466}
2467
2468svn_error_t *
2469svn_client_switch(svn_revnum_t *result_rev,
2470                  const char *path,
2471                  const char *switch_url,
2472                  const svn_opt_revision_t *revision,
2473                  svn_boolean_t recurse,
2474                  svn_client_ctx_t *ctx,
2475                  apr_pool_t *pool)
2476{
2477  svn_opt_revision_t peg_revision;
2478  peg_revision.kind = svn_opt_revision_unspecified;
2479  return svn_client_switch2(result_rev, path, switch_url,
2480                            &peg_revision, revision,
2481                            SVN_DEPTH_INFINITY_OR_FILES(recurse),
2482                            FALSE, FALSE, FALSE, ctx, pool);
2483}
2484
2485/*** From cat.c ***/
2486svn_error_t *
2487svn_client_cat2(svn_stream_t *out,
2488                const char *path_or_url,
2489                const svn_opt_revision_t *peg_revision,
2490                const svn_opt_revision_t *revision,
2491                svn_client_ctx_t *ctx,
2492                apr_pool_t *pool)
2493{
2494  return svn_client_cat3(NULL /* props */,
2495                         out, path_or_url, peg_revision, revision,
2496                         TRUE /* expand_keywords */,
2497                         ctx, pool, pool);
2498}
2499
2500
2501svn_error_t *
2502svn_client_cat(svn_stream_t *out,
2503               const char *path_or_url,
2504               const svn_opt_revision_t *revision,
2505               svn_client_ctx_t *ctx,
2506               apr_pool_t *pool)
2507{
2508  return svn_client_cat2(out, path_or_url, revision, revision,
2509                         ctx, pool);
2510}
2511
2512/*** From checkout.c ***/
2513svn_error_t *
2514svn_client_checkout2(svn_revnum_t *result_rev,
2515                     const char *URL,
2516                     const char *path,
2517                     const svn_opt_revision_t *peg_revision,
2518                     const svn_opt_revision_t *revision,
2519                     svn_boolean_t recurse,
2520                     svn_boolean_t ignore_externals,
2521                     svn_client_ctx_t *ctx,
2522                     apr_pool_t *pool)
2523{
2524  return svn_error_trace(svn_client_checkout3(result_rev, URL, path,
2525                                        peg_revision, revision,
2526                                        SVN_DEPTH_INFINITY_OR_FILES(recurse),
2527                                        ignore_externals, FALSE, ctx, pool));
2528}
2529
2530svn_error_t *
2531svn_client_checkout(svn_revnum_t *result_rev,
2532                    const char *URL,
2533                    const char *path,
2534                    const svn_opt_revision_t *revision,
2535                    svn_boolean_t recurse,
2536                    svn_client_ctx_t *ctx,
2537                    apr_pool_t *pool)
2538{
2539  svn_opt_revision_t peg_revision;
2540
2541  peg_revision.kind = svn_opt_revision_unspecified;
2542
2543  return svn_error_trace(svn_client_checkout2(result_rev, URL, path,
2544                                              &peg_revision, revision, recurse,
2545                                              FALSE, ctx, pool));
2546}
2547
2548/*** From info.c ***/
2549
2550svn_error_t *
2551svn_client_info3(const char *abspath_or_url,
2552                 const svn_opt_revision_t *peg_revision,
2553                 const svn_opt_revision_t *revision,
2554                 svn_depth_t depth,
2555                 svn_boolean_t fetch_excluded,
2556                 svn_boolean_t fetch_actual_only,
2557                 const apr_array_header_t *changelists,
2558                 svn_client_info_receiver2_t receiver,
2559                 void *receiver_baton,
2560                 svn_client_ctx_t *ctx,
2561                 apr_pool_t *pool)
2562{
2563  return svn_error_trace(
2564            svn_client_info4(abspath_or_url,
2565                             peg_revision,
2566                             revision,
2567                             depth,
2568                             fetch_excluded,
2569                             fetch_actual_only,
2570                             FALSE /* include_externals */,
2571                             changelists,
2572                             receiver, receiver_baton,
2573                             ctx, pool));
2574}
2575
2576svn_info_t *
2577svn_info_dup(const svn_info_t *info, apr_pool_t *pool)
2578{
2579  svn_info_t *dupinfo = apr_palloc(pool, sizeof(*dupinfo));
2580
2581  /* Perform a trivial copy ... */
2582  *dupinfo = *info;
2583
2584  /* ...and then re-copy stuff that needs to be duped into our pool. */
2585  if (info->URL)
2586    dupinfo->URL = apr_pstrdup(pool, info->URL);
2587  if (info->repos_root_URL)
2588    dupinfo->repos_root_URL = apr_pstrdup(pool, info->repos_root_URL);
2589  if (info->repos_UUID)
2590    dupinfo->repos_UUID = apr_pstrdup(pool, info->repos_UUID);
2591  if (info->last_changed_author)
2592    dupinfo->last_changed_author = apr_pstrdup(pool,
2593                                               info->last_changed_author);
2594  if (info->lock)
2595    dupinfo->lock = svn_lock_dup(info->lock, pool);
2596  if (info->copyfrom_url)
2597    dupinfo->copyfrom_url = apr_pstrdup(pool, info->copyfrom_url);
2598  if (info->checksum)
2599    dupinfo->checksum = apr_pstrdup(pool, info->checksum);
2600  if (info->conflict_old)
2601    dupinfo->conflict_old = apr_pstrdup(pool, info->conflict_old);
2602  if (info->conflict_new)
2603    dupinfo->conflict_new = apr_pstrdup(pool, info->conflict_new);
2604  if (info->conflict_wrk)
2605    dupinfo->conflict_wrk = apr_pstrdup(pool, info->conflict_wrk);
2606  if (info->prejfile)
2607    dupinfo->prejfile = apr_pstrdup(pool, info->prejfile);
2608
2609  return dupinfo;
2610}
2611
2612/* Convert an svn_client_info2_t to an svn_info_t, doing shallow copies. */
2613static svn_error_t *
2614info_from_info2(svn_info_t **new_info,
2615                svn_wc_context_t *wc_ctx,
2616                const svn_client_info2_t *info2,
2617                apr_pool_t *pool)
2618{
2619  svn_info_t *info = apr_pcalloc(pool, sizeof(*info));
2620
2621  info->URL                 = info2->URL;
2622  /* Goofy backward compat handling for added nodes. */
2623  if (SVN_IS_VALID_REVNUM(info2->rev))
2624    info->rev               = info2->rev;
2625  else
2626    info->rev               = 0;
2627
2628  info->kind                = info2->kind;
2629  info->repos_root_URL      = info2->repos_root_URL;
2630  info->repos_UUID          = info2->repos_UUID;
2631  info->last_changed_rev    = info2->last_changed_rev;
2632  info->last_changed_date   = info2->last_changed_date;
2633  info->last_changed_author = info2->last_changed_author;
2634
2635  /* Stupid old structure has a non-const LOCK member. Sigh.  */
2636  info->lock                = (svn_lock_t *)info2->lock;
2637
2638  info->size64              = info2->size;
2639  if (info2->size == SVN_INVALID_FILESIZE)
2640    info->size               = SVN_INFO_SIZE_UNKNOWN;
2641  else if (((svn_filesize_t)(apr_size_t)info->size64) == info->size64)
2642    info->size               = (apr_size_t)info->size64;
2643  else /* >= 4GB */
2644    info->size               = SVN_INFO_SIZE_UNKNOWN;
2645
2646  if (info2->wc_info)
2647    {
2648      info->has_wc_info         = TRUE;
2649      info->schedule            = info2->wc_info->schedule;
2650      info->copyfrom_url        = info2->wc_info->copyfrom_url;
2651      info->copyfrom_rev        = info2->wc_info->copyfrom_rev;
2652      info->text_time           = info2->wc_info->recorded_time;
2653      info->prop_time           = 0;
2654      if (info2->wc_info->checksum
2655            && info2->wc_info->checksum->kind == svn_checksum_md5)
2656        info->checksum          = svn_checksum_to_cstring(
2657                                        info2->wc_info->checksum, pool);
2658      else
2659        info->checksum          = NULL;
2660      info->changelist          = info2->wc_info->changelist;
2661      info->depth               = info2->wc_info->depth;
2662
2663      if (info->depth == svn_depth_unknown && info->kind == svn_node_file)
2664        info->depth = svn_depth_infinity;
2665
2666      info->working_size64      = info2->wc_info->recorded_size;
2667      if (((svn_filesize_t)(apr_size_t)info->working_size64) == info->working_size64)
2668        info->working_size       = (apr_size_t)info->working_size64;
2669      else /* >= 4GB */
2670        info->working_size       = SVN_INFO_SIZE_UNKNOWN;
2671    }
2672  else
2673    {
2674      info->has_wc_info           = FALSE;
2675      info->working_size          = SVN_INFO_SIZE_UNKNOWN;
2676      info->working_size64        = SVN_INVALID_FILESIZE;
2677      info->depth                 = svn_depth_unknown;
2678    }
2679
2680  /* Populate conflict fields. */
2681  if (info2->wc_info && info2->wc_info->conflicts)
2682    {
2683      int i;
2684
2685      for (i = 0; i < info2->wc_info->conflicts->nelts; i++)
2686        {
2687          const svn_wc_conflict_description2_t *conflict
2688                              = APR_ARRAY_IDX(info2->wc_info->conflicts, i,
2689                                    const svn_wc_conflict_description2_t *);
2690
2691          /* ### Not really sure what we should do if we get multiple
2692             ### conflicts of the same type. */
2693          switch (conflict->kind)
2694            {
2695              case svn_wc_conflict_kind_tree:
2696                info->tree_conflict = svn_wc__cd2_to_cd(conflict, pool);
2697                break;
2698
2699              case svn_wc_conflict_kind_text:
2700                info->conflict_old = conflict->base_abspath;
2701                info->conflict_new = conflict->my_abspath;
2702                info->conflict_wrk = conflict->their_abspath;
2703                break;
2704
2705              case svn_wc_conflict_kind_property:
2706                info->prejfile = conflict->their_abspath;
2707                break;
2708            }
2709        }
2710    }
2711
2712  if (info2->wc_info && info2->wc_info->checksum)
2713    {
2714      const svn_checksum_t *md5_checksum;
2715
2716      SVN_ERR(svn_wc__node_get_md5_from_sha1(&md5_checksum,
2717                                             wc_ctx,
2718                                             info2->wc_info->wcroot_abspath,
2719                                             info2->wc_info->checksum,
2720                                             pool, pool));
2721
2722      info->checksum = svn_checksum_to_cstring(md5_checksum, pool);
2723    }
2724
2725  *new_info = info;
2726  return SVN_NO_ERROR;
2727}
2728
2729struct info_to_relpath_baton
2730{
2731  const char *anchor_abspath;
2732  const char *anchor_relpath;
2733  svn_info_receiver_t info_receiver;
2734  void *info_baton;
2735  svn_wc_context_t *wc_ctx;
2736};
2737
2738static svn_error_t *
2739info_receiver_relpath_wrapper(void *baton,
2740                              const char *abspath_or_url,
2741                              const svn_client_info2_t *info2,
2742                              apr_pool_t *scratch_pool)
2743{
2744  struct info_to_relpath_baton *rb = baton;
2745  const char *path = abspath_or_url;
2746  svn_info_t *info;
2747
2748  if (rb->anchor_relpath &&
2749      svn_dirent_is_ancestor(rb->anchor_abspath, abspath_or_url))
2750    {
2751      path = svn_dirent_join(rb->anchor_relpath,
2752                             svn_dirent_skip_ancestor(rb->anchor_abspath,
2753                                                      abspath_or_url),
2754                             scratch_pool);
2755    }
2756
2757  SVN_ERR(info_from_info2(&info, rb->wc_ctx, info2, scratch_pool));
2758
2759  SVN_ERR(rb->info_receiver(rb->info_baton,
2760                            path,
2761                            info,
2762                            scratch_pool));
2763
2764  return SVN_NO_ERROR;
2765}
2766
2767svn_error_t *
2768svn_client_info2(const char *path_or_url,
2769                 const svn_opt_revision_t *peg_revision,
2770                 const svn_opt_revision_t *revision,
2771                 svn_info_receiver_t receiver,
2772                 void *receiver_baton,
2773                 svn_depth_t depth,
2774                 const apr_array_header_t *changelists,
2775                 svn_client_ctx_t *ctx,
2776                 apr_pool_t *pool)
2777{
2778  struct info_to_relpath_baton rb;
2779  const char *abspath_or_url = path_or_url;
2780
2781  rb.anchor_relpath = NULL;
2782  rb.info_receiver = receiver;
2783  rb.info_baton = receiver_baton;
2784  rb.wc_ctx = ctx->wc_ctx;
2785
2786  if (!svn_path_is_url(path_or_url))
2787    {
2788      SVN_ERR(svn_dirent_get_absolute(&abspath_or_url, path_or_url, pool));
2789      rb.anchor_abspath = abspath_or_url;
2790      rb.anchor_relpath = path_or_url;
2791    }
2792
2793  SVN_ERR(svn_client_info3(abspath_or_url,
2794                           peg_revision,
2795                           revision,
2796                           depth,
2797                           FALSE, TRUE,
2798                           changelists,
2799                           info_receiver_relpath_wrapper,
2800                           &rb,
2801                           ctx,
2802                           pool));
2803
2804  return SVN_NO_ERROR;
2805}
2806
2807svn_error_t *
2808svn_client_info(const char *path_or_url,
2809                const svn_opt_revision_t *peg_revision,
2810                const svn_opt_revision_t *revision,
2811                svn_info_receiver_t receiver,
2812                void *receiver_baton,
2813                svn_boolean_t recurse,
2814                svn_client_ctx_t *ctx,
2815                apr_pool_t *pool)
2816{
2817  return svn_client_info2(path_or_url, peg_revision, revision,
2818                          receiver, receiver_baton,
2819                          SVN_DEPTH_INFINITY_OR_EMPTY(recurse),
2820                          NULL, ctx, pool);
2821}
2822
2823/*** From resolved.c ***/
2824svn_error_t *
2825svn_client_resolved(const char *path,
2826                    svn_boolean_t recursive,
2827                    svn_client_ctx_t *ctx,
2828                    apr_pool_t *pool)
2829{
2830  svn_depth_t depth = SVN_DEPTH_INFINITY_OR_EMPTY(recursive);
2831  return svn_client_resolve(path, depth,
2832                            svn_wc_conflict_choose_merged, ctx, pool);
2833}
2834/*** From revert.c ***/
2835svn_error_t *
2836svn_client_revert2(const apr_array_header_t *paths,
2837                   svn_depth_t depth,
2838                   const apr_array_header_t *changelists,
2839                   svn_client_ctx_t *ctx,
2840                   apr_pool_t *pool)
2841{
2842  return svn_error_trace(svn_client_revert3(paths,
2843                                            depth,
2844                                            changelists,
2845                                            FALSE /* clear_changelists */,
2846                                            FALSE /* metadata_only */,
2847                                            ctx,
2848                                            pool));
2849}
2850
2851svn_error_t *
2852svn_client_revert(const apr_array_header_t *paths,
2853                  svn_boolean_t recursive,
2854                  svn_client_ctx_t *ctx,
2855                  apr_pool_t *pool)
2856{
2857  return svn_client_revert2(paths, SVN_DEPTH_INFINITY_OR_EMPTY(recursive),
2858                            NULL, ctx, pool);
2859}
2860
2861/*** From ra.c ***/
2862svn_error_t *
2863svn_client_open_ra_session(svn_ra_session_t **session,
2864                           const char *url,
2865                           svn_client_ctx_t *ctx,
2866                           apr_pool_t *pool)
2867{
2868  return svn_error_trace(
2869             svn_client_open_ra_session2(session, url,
2870                                         NULL, ctx,
2871                                         pool, pool));
2872}
2873
2874svn_error_t *
2875svn_client_uuid_from_url(const char **uuid,
2876                         const char *url,
2877                         svn_client_ctx_t *ctx,
2878                         apr_pool_t *pool)
2879{
2880  svn_error_t *err;
2881  apr_pool_t *subpool = svn_pool_create(pool);
2882
2883  err = svn_client_get_repos_root(NULL, uuid, url,
2884                                  ctx, pool, subpool);
2885  /* destroy the RA session */
2886  svn_pool_destroy(subpool);
2887
2888  return svn_error_trace(err);
2889}
2890
2891svn_error_t *
2892svn_client_uuid_from_path2(const char **uuid,
2893                           const char *local_abspath,
2894                           svn_client_ctx_t *ctx,
2895                           apr_pool_t *result_pool,
2896                           apr_pool_t *scratch_pool)
2897{
2898  return svn_error_trace(
2899      svn_client_get_repos_root(NULL, uuid,
2900                                local_abspath, ctx,
2901                                result_pool, scratch_pool));
2902}
2903
2904svn_error_t *
2905svn_client_uuid_from_path(const char **uuid,
2906                          const char *path,
2907                          svn_wc_adm_access_t *adm_access,
2908                          svn_client_ctx_t *ctx,
2909                          apr_pool_t *pool)
2910{
2911  const char *local_abspath;
2912
2913  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
2914  return svn_error_trace(
2915    svn_client_uuid_from_path2(uuid, local_abspath, ctx, pool, pool));
2916}
2917
2918/*** From url.c ***/
2919svn_error_t *
2920svn_client_root_url_from_path(const char **url,
2921                              const char *path_or_url,
2922                              svn_client_ctx_t *ctx,
2923                              apr_pool_t *pool)
2924{
2925  apr_pool_t *subpool = svn_pool_create(pool);
2926  svn_error_t *err;
2927  if (!svn_path_is_url(path_or_url))
2928    SVN_ERR(svn_dirent_get_absolute(&path_or_url, path_or_url, pool));
2929
2930  err = svn_client_get_repos_root(url, NULL, path_or_url,
2931                                  ctx, pool, subpool);
2932
2933  /* close ra session */
2934  svn_pool_destroy(subpool);
2935  return svn_error_trace(err);
2936}
2937
2938svn_error_t *
2939svn_client_url_from_path(const char **url,
2940                         const char *path_or_url,
2941                         apr_pool_t *pool)
2942{
2943  svn_client_ctx_t *ctx;
2944
2945  SVN_ERR(svn_client_create_context(&ctx, pool));
2946
2947  return svn_client_url_from_path2(url, path_or_url, ctx, pool, pool);
2948}
2949
2950/*** From mergeinfo.c ***/
2951svn_error_t *
2952svn_client_mergeinfo_log(svn_boolean_t finding_merged,
2953                         const char *target_path_or_url,
2954                         const svn_opt_revision_t *target_peg_revision,
2955                         const char *source_path_or_url,
2956                         const svn_opt_revision_t *source_peg_revision,
2957                         svn_log_entry_receiver_t receiver,
2958                         void *receiver_baton,
2959                         svn_boolean_t discover_changed_paths,
2960                         svn_depth_t depth,
2961                         const apr_array_header_t *revprops,
2962                         svn_client_ctx_t *ctx,
2963                         apr_pool_t *scratch_pool)
2964{
2965  svn_opt_revision_t start_revision, end_revision;
2966
2967  start_revision.kind = svn_opt_revision_unspecified;
2968  end_revision.kind = svn_opt_revision_unspecified;
2969
2970  return svn_client_mergeinfo_log2(finding_merged,
2971                                   target_path_or_url, target_peg_revision,
2972                                   source_path_or_url, source_peg_revision,
2973                                   &start_revision, &end_revision,
2974                                   receiver, receiver_baton,
2975                                   discover_changed_paths, depth, revprops,
2976                                   ctx, scratch_pool);
2977}
2978
2979svn_error_t *
2980svn_client_mergeinfo_log_merged(const char *path_or_url,
2981                                const svn_opt_revision_t *peg_revision,
2982                                const char *merge_source_path_or_url,
2983                                const svn_opt_revision_t *src_peg_revision,
2984                                svn_log_entry_receiver_t log_receiver,
2985                                void *log_receiver_baton,
2986                                svn_boolean_t discover_changed_paths,
2987                                const apr_array_header_t *revprops,
2988                                svn_client_ctx_t *ctx,
2989                                apr_pool_t *pool)
2990{
2991  return svn_client_mergeinfo_log(TRUE, path_or_url, peg_revision,
2992                                  merge_source_path_or_url,
2993                                  src_peg_revision,
2994                                  log_receiver, log_receiver_baton,
2995                                  discover_changed_paths,
2996                                  svn_depth_empty, revprops, ctx,
2997                                  pool);
2998}
2999
3000svn_error_t *
3001svn_client_mergeinfo_log_eligible(const char *path_or_url,
3002                                  const svn_opt_revision_t *peg_revision,
3003                                  const char *merge_source_path_or_url,
3004                                  const svn_opt_revision_t *src_peg_revision,
3005                                  svn_log_entry_receiver_t log_receiver,
3006                                  void *log_receiver_baton,
3007                                  svn_boolean_t discover_changed_paths,
3008                                  const apr_array_header_t *revprops,
3009                                  svn_client_ctx_t *ctx,
3010                                  apr_pool_t *pool)
3011{
3012  return svn_client_mergeinfo_log(FALSE, path_or_url, peg_revision,
3013                                  merge_source_path_or_url,
3014                                  src_peg_revision,
3015                                  log_receiver, log_receiver_baton,
3016                                  discover_changed_paths,
3017                                  svn_depth_empty, revprops, ctx,
3018                                  pool);
3019}
3020
3021/*** From relocate.c ***/
3022svn_error_t *
3023svn_client_relocate(const char *path,
3024                    const char *from_prefix,
3025                    const char *to_prefix,
3026                    svn_boolean_t recurse,
3027                    svn_client_ctx_t *ctx,
3028                    apr_pool_t *pool)
3029{
3030  if (! recurse)
3031    SVN_ERR(svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
3032                             _("Non-recursive relocation not supported")));
3033  return svn_client_relocate2(path, from_prefix, to_prefix, TRUE, ctx, pool);
3034}
3035
3036/*** From util.c ***/
3037svn_error_t *
3038svn_client_commit_item_create(const svn_client_commit_item3_t **item,
3039                              apr_pool_t *pool)
3040{
3041  *item = svn_client_commit_item3_create(pool);
3042  return SVN_NO_ERROR;
3043}
3044
3045svn_client_commit_item2_t *
3046svn_client_commit_item2_dup(const svn_client_commit_item2_t *item,
3047                            apr_pool_t *pool)
3048{
3049  svn_client_commit_item2_t *new_item = apr_palloc(pool, sizeof(*new_item));
3050
3051  *new_item = *item;
3052
3053  if (new_item->path)
3054    new_item->path = apr_pstrdup(pool, new_item->path);
3055
3056  if (new_item->url)
3057    new_item->url = apr_pstrdup(pool, new_item->url);
3058
3059  if (new_item->copyfrom_url)
3060    new_item->copyfrom_url = apr_pstrdup(pool, new_item->copyfrom_url);
3061
3062  if (new_item->wcprop_changes)
3063    new_item->wcprop_changes = svn_prop_array_dup(new_item->wcprop_changes,
3064                                                  pool);
3065
3066  return new_item;
3067}
3068
3069svn_error_t *
3070svn_client_cleanup(const char *path,
3071                   svn_client_ctx_t *ctx,
3072                   apr_pool_t *scratch_pool)
3073{
3074  const char *local_abspath;
3075
3076  if (svn_path_is_url(path))
3077    return svn_error_createf(SVN_ERR_ILLEGAL_TARGET, NULL,
3078                             _("'%s' is not a local path"), path);
3079
3080  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
3081
3082  return svn_error_trace(svn_client_cleanup2(local_abspath,
3083                                             TRUE /* break_locks */,
3084                                             TRUE /* fix_recorded_timestamps */,
3085                                             TRUE /* clear_dav_cache */,
3086                                             TRUE /* vacuum_pristines */,
3087                                             FALSE /* include_externals */,
3088                                             ctx, scratch_pool));
3089}
3090