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