~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/bindings/javahl/native/SVNClient.cpp

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
24
24
 * @brief: Implementation of the SVNClient class
25
25
 */
26
26
 
 
27
#include <vector>
 
28
#include <iostream>
 
29
#include <sstream>
 
30
#include <string>
 
31
 
27
32
#include "SVNClient.h"
28
33
#include "JNIUtil.h"
29
34
#include "CopySources.h"
30
35
#include "DiffSummaryReceiver.h"
31
36
#include "ClientContext.h"
32
37
#include "Prompter.h"
 
38
#include "RemoteSession.h"
33
39
#include "Pool.h"
34
40
#include "Targets.h"
35
41
#include "Revision.h"
50
56
#include "CommitMessage.h"
51
57
#include "EnumMapper.h"
52
58
#include "StringArray.h"
53
 
#include "RevpropTable.h"
 
59
#include "PropertyTable.h"
54
60
#include "DiffOptions.h"
55
61
#include "CreateJ.h"
 
62
#include "JNIStringHolder.h"
 
63
 
56
64
#include "svn_auth.h"
57
65
#include "svn_dso.h"
58
66
#include "svn_types.h"
62
70
#include "svn_diff.h"
63
71
#include "svn_config.h"
64
72
#include "svn_io.h"
 
73
#include "svn_hash.h"
65
74
#include "svn_dirent_uri.h"
66
75
#include "svn_path.h"
67
76
#include "svn_utf.h"
 
77
#include "private/svn_subr_private.h"
68
78
#include "svn_private_config.h"
69
 
#include "JNIStringHolder.h"
70
 
#include <vector>
71
 
#include <iostream>
72
 
#include <sstream>
 
79
 
 
80
#include "ExternalItem.hpp"
 
81
#include "jniwrapper/jni_list.hpp"
 
82
#include "jniwrapper/jni_stack.hpp"
 
83
#include "jniwrapper/jni_string_map.hpp"
73
84
 
74
85
 
75
86
SVNClient::SVNClient(jobject jthis_in)
85
96
{
86
97
    static jfieldID fid = 0;
87
98
    jlong cppAddr = SVNBase::findCppAddrForJObject(jthis, &fid,
88
 
                                                   JAVA_PACKAGE"/SVNClient");
 
99
                                                   JAVAHL_CLASS("/SVNClient"));
89
100
    return (cppAddr == 0 ? NULL : reinterpret_cast<SVNClient *>(cppAddr));
90
101
}
91
102
 
92
103
void SVNClient::dispose(jobject jthis)
93
104
{
94
105
    static jfieldID fid = 0;
95
 
    SVNBase::dispose(jthis, &fid, JAVA_PACKAGE"/SVNClient");
 
106
    SVNBase::dispose(jthis, &fid, JAVAHL_CLASS("/SVNClient"));
96
107
}
97
108
 
98
109
jobject SVNClient::getVersionExtended(bool verbose)
99
110
{
100
111
    JNIEnv *const env = JNIUtil::getEnv();
101
112
 
102
 
    jclass clazz = env->FindClass(JAVA_PACKAGE"/types/VersionExtended");
 
113
    jclass clazz = env->FindClass(JAVAHL_CLASS("/types/VersionExtended"));
103
114
    if (JNIUtil::isJavaExceptionThrown())
104
115
        return NULL;
105
116
 
184
195
 
185
196
void
186
197
SVNClient::status(const char *path, svn_depth_t depth,
187
 
                  bool onServer, bool getAll, bool noIgnore,
188
 
                  bool ignoreExternals, StringArray &changelists,
 
198
                  bool onServer, bool onDisk, bool getAll,
 
199
                  bool noIgnore, bool ignoreExternals,
 
200
                  bool depthAsSticky, StringArray &changelists,
189
201
                  StatusCallback *callback)
190
202
{
191
203
    SVN::Pool subPool(pool);
204
216
 
205
217
    rev.kind = svn_opt_revision_unspecified;
206
218
 
207
 
    SVN_JNI_ERR(svn_client_status5(&youngest, ctx, checkedPath.c_str(),
208
 
                                   &rev,
209
 
                                   depth,
210
 
                                   getAll, onServer, noIgnore, ignoreExternals,
211
 
                                   FALSE,
 
219
    SVN_JNI_ERR(svn_client_status6(&youngest, ctx, checkedPath.c_str(),
 
220
                                   &rev, depth,
 
221
                                   getAll, onServer, onDisk,
 
222
                                   noIgnore, ignoreExternals, depthAsSticky,
212
223
                                   changelists.array(subPool),
213
224
                                   StatusCallback::callback, callback,
214
225
                                   subPool.getPool()), );
227
238
    std::vector<RevisionRange>::const_iterator it;
228
239
    for (it = revRanges.begin(); it != revRanges.end(); ++it)
229
240
    {
230
 
        if (it->toRange(subPool)->start.kind
231
 
            == svn_opt_revision_unspecified
232
 
            && it->toRange(subPool)->end.kind
233
 
            == svn_opt_revision_unspecified)
 
241
        const svn_opt_revision_range_t *range = it->toRange(subPool);
 
242
 
 
243
        if (range->start.kind == svn_opt_revision_unspecified
 
244
            && range->end.kind == svn_opt_revision_unspecified)
234
245
        {
235
 
            svn_opt_revision_range_t *range =
 
246
            svn_opt_revision_range_t *full =
236
247
                reinterpret_cast<svn_opt_revision_range_t *>
237
248
                    (apr_pcalloc(subPool.getPool(), sizeof(*range)));
238
 
            range->start.kind = svn_opt_revision_number;
239
 
            range->start.value.number = 1;
240
 
            range->end.kind = svn_opt_revision_head;
 
249
            full->start.kind = svn_opt_revision_number;
 
250
            full->start.value.number = 1;
 
251
            full->end.kind = svn_opt_revision_head;
 
252
            full->end.value.number = 0;
 
253
            APR_ARRAY_PUSH(ranges, const svn_opt_revision_range_t *) = full;
 
254
        }
 
255
        else
 
256
        {
241
257
            APR_ARRAY_PUSH(ranges, const svn_opt_revision_range_t *) = range;
242
258
        }
243
 
        else
244
 
        {
245
 
            APR_ARRAY_PUSH(ranges, const svn_opt_revision_range_t *) =
246
 
                it->toRange(subPool);
247
 
        }
248
259
        if (JNIUtil::isExceptionThrown())
249
260
            return NULL;
250
261
    }
255
266
                            std::vector<RevisionRange> &logRanges,
256
267
                            bool stopOnCopy, bool discoverPaths,
257
268
                            bool includeMergedRevisions, StringArray &revProps,
258
 
                            long limit, LogMessageCallback *callback)
 
269
                            int limit, LogMessageCallback *callback)
259
270
{
260
271
    SVN::Pool subPool(pool);
261
272
 
317
328
}
318
329
 
319
330
void SVNClient::remove(Targets &targets, CommitMessage *message, bool force,
320
 
                       bool keep_local, RevpropTable &revprops,
 
331
                       bool keep_local, PropertyTable &revprops,
321
332
                       CommitCallback *callback)
322
333
{
323
334
    SVN::Pool subPool(pool);
334
345
                                   ctx, subPool.getPool()), );
335
346
}
336
347
 
337
 
void SVNClient::revert(const char *path, svn_depth_t depth,
338
 
                       StringArray &changelists)
 
348
void SVNClient::revert(StringArray &paths, svn_depth_t depth,
 
349
                       StringArray &changelists,
 
350
                       bool clear_changelists,
 
351
                       bool metadata_only)
339
352
{
340
353
    SVN::Pool subPool(pool);
341
354
 
342
 
    SVN_JNI_NULL_PTR_EX(path, "path", );
343
 
 
344
355
    svn_client_ctx_t *ctx = context.getContext(NULL, subPool);
345
356
    if (ctx == NULL)
346
357
        return;
347
358
 
348
 
    Targets target(path, subPool);
349
 
    const apr_array_header_t *targets = target.array(subPool);
350
 
    SVN_JNI_ERR(target.error_occurred(), );
351
 
    SVN_JNI_ERR(svn_client_revert2(targets, depth,
352
 
                                   changelists.array(subPool), ctx,
353
 
                                   subPool.getPool()), );
 
359
    Targets targets(paths, subPool);
 
360
    SVN_JNI_ERR(targets.error_occurred(), );
 
361
    SVN_JNI_ERR(svn_client_revert3(targets.array(subPool), depth,
 
362
                                   changelists.array(subPool),
 
363
                                   clear_changelists,
 
364
                                   metadata_only,
 
365
                                   ctx, subPool.getPool()), );
354
366
}
355
367
 
356
368
void SVNClient::add(const char *path,
417
429
 
418
430
void SVNClient::commit(Targets &targets, CommitMessage *message,
419
431
                       svn_depth_t depth, bool noUnlock, bool keepChangelist,
420
 
                       StringArray &changelists, RevpropTable &revprops,
 
432
                       StringArray &changelists, PropertyTable &revprops,
421
433
                       CommitCallback *callback)
422
434
{
423
435
    SVN::Pool subPool(pool);
439
451
                );
440
452
}
441
453
 
 
454
 
 
455
namespace {
 
456
typedef Java::ImmutableList<JavaHL::ExternalItem> PinList;
 
457
typedef Java::ImmutableMap<PinList> PinMap;
 
458
 
 
459
struct PinListFunctor
 
460
{
 
461
  explicit PinListFunctor(const Java::Env& env, SVN::Pool& pool, int refs_len)
 
462
    : m_pool(pool),
 
463
      m_refs(apr_array_make(pool.getPool(), refs_len,
 
464
                            sizeof(svn_wc_external_item2_t*)))
 
465
      {}
 
466
 
 
467
  void operator()(const JavaHL::ExternalItem& item)
 
468
    {
 
469
      APR_ARRAY_PUSH(m_refs, svn_wc_external_item2_t*) =
 
470
        item.get_external_item(m_pool);
 
471
    }
 
472
 
 
473
  SVN::Pool& m_pool;
 
474
  apr_array_header_t *m_refs;
 
475
};
 
476
 
 
477
struct PinMapFunctor
 
478
{
 
479
  explicit PinMapFunctor(const Java::Env& env, SVN::Pool& pool)
 
480
    : m_env(env),
 
481
      m_pool(pool),
 
482
      m_pin_set(svn_hash__make(pool.getPool()))
 
483
    {}
 
484
 
 
485
  void operator()(const std::string& path, const PinList& refs)
 
486
    {
 
487
      PinListFunctor lf(m_env, m_pool, refs.length());
 
488
      refs.for_each(lf);
 
489
      const char* key = static_cast<const char*>(
 
490
          apr_pmemdup(m_pool.getPool(), path.c_str(), path.size() + 1));
 
491
      svn_hash_sets(m_pin_set, key, lf.m_refs);
 
492
    }
 
493
 
 
494
  const Java::Env& m_env;
 
495
  SVN::Pool& m_pool;
 
496
  apr_hash_t *m_pin_set;
 
497
};
 
498
 
 
499
apr_hash_t *get_externals_to_pin(jobject jexternalsToPin, SVN::Pool& pool)
 
500
{
 
501
  if (!jexternalsToPin)
 
502
    return NULL;
 
503
 
 
504
  const Java::Env env;
 
505
  JNIEnv *jenv = env.get();
 
506
 
 
507
  try
 
508
    {
 
509
      PinMap pin_map(env, jexternalsToPin);
 
510
      PinMapFunctor mf(env, pool);
 
511
      pin_map.for_each(mf);
 
512
      return mf.m_pin_set;
 
513
    }
 
514
  SVN_JAVAHL_JNI_CATCH;
 
515
  return NULL;
 
516
}
 
517
} // anonymous namespace
 
518
 
442
519
void SVNClient::copy(CopySources &copySources, const char *destPath,
443
520
                     CommitMessage *message, bool copyAsChild,
444
521
                     bool makeParents, bool ignoreExternals,
445
 
                     RevpropTable &revprops, CommitCallback *callback)
 
522
                     bool metadataOnly,
 
523
                     bool pinExternals, jobject jexternalsToPin,
 
524
                     PropertyTable &revprops, CommitCallback *callback)
446
525
{
447
526
    SVN::Pool subPool(pool);
448
527
 
449
528
    apr_array_header_t *srcs = copySources.array(subPool);
450
 
    if (srcs == NULL)
451
 
    {
452
 
        JNIUtil::throwNativeException(JAVA_PACKAGE "/ClientException",
453
 
                                      "Invalid copy sources");
454
 
        return;
455
 
    }
 
529
    SVN_JNI_NULL_PTR_EX(srcs, "sources", );
456
530
    SVN_JNI_NULL_PTR_EX(destPath, "destPath", );
457
531
    Path destinationPath(destPath, subPool);
458
532
    SVN_JNI_ERR(destinationPath.error_occurred(), );
461
535
    if (ctx == NULL)
462
536
        return;
463
537
 
464
 
    SVN_JNI_ERR(svn_client_copy6(srcs, destinationPath.c_str(),
465
 
                                 copyAsChild, makeParents, ignoreExternals,
466
 
                                 revprops.hash(subPool),
467
 
                                 CommitCallback::callback, callback,
 
538
    apr_hash_t *pin_set = get_externals_to_pin(jexternalsToPin, subPool);
 
539
    if (!JNIUtil::isJavaExceptionThrown())
 
540
      SVN_JNI_ERR(svn_client_copy7(srcs, destinationPath.c_str(),
 
541
                                   copyAsChild, makeParents, ignoreExternals,
 
542
                                   metadataOnly,
 
543
                                   pinExternals, pin_set,
 
544
                                   revprops.hash(subPool),
 
545
                                   CommitCallback::callback, callback,
468
546
                                 ctx, subPool.getPool()), );
469
547
}
470
548
 
471
549
void SVNClient::move(Targets &srcPaths, const char *destPath,
472
550
                     CommitMessage *message, bool force, bool moveAsChild,
473
551
                     bool makeParents, bool metadataOnly, bool allowMixRev,
474
 
                     RevpropTable &revprops, CommitCallback *callback)
 
552
                     PropertyTable &revprops, CommitCallback *callback)
475
553
{
476
554
    SVN::Pool subPool(pool);
477
555
 
496
574
}
497
575
 
498
576
void SVNClient::mkdir(Targets &targets, CommitMessage *message,
499
 
                      bool makeParents, RevpropTable &revprops,
 
577
                      bool makeParents, PropertyTable &revprops,
500
578
                      CommitCallback *callback)
501
579
{
502
580
    SVN::Pool subPool(pool);
513
591
                                  ctx, subPool.getPool()), );
514
592
}
515
593
 
516
 
void SVNClient::cleanup(const char *path)
 
594
void SVNClient::cleanup(const char *path,
 
595
                        bool break_locks,
 
596
                        bool fix_recorded_timestamps,
 
597
                        bool clear_dav_cache,
 
598
                        bool remove_unused_pristines,
 
599
                        bool include_externals)
517
600
{
518
601
    SVN::Pool subPool(pool);
519
602
    SVN_JNI_NULL_PTR_EX(path, "path", );
524
607
    if (ctx == NULL)
525
608
        return;
526
609
 
527
 
    SVN_JNI_ERR(svn_client_cleanup(intPath.c_str(), ctx, subPool.getPool()),);
 
610
    SVN_JNI_ERR(svn_client_cleanup2(intPath.c_str(),
 
611
                                    break_locks,
 
612
                                    fix_recorded_timestamps,
 
613
                                    clear_dav_cache,
 
614
                                    remove_unused_pristines,
 
615
                                    include_externals,
 
616
                                    ctx, subPool.getPool()),);
528
617
}
529
618
 
530
619
void SVNClient::resolve(const char *path, svn_depth_t depth,
545
634
jlong SVNClient::doExport(const char *srcPath, const char *destPath,
546
635
                          Revision &revision, Revision &pegRevision,
547
636
                          bool force, bool ignoreExternals,
 
637
                          bool ignoreKeywords,
548
638
                          svn_depth_t depth, const char *nativeEOL)
549
639
{
550
640
    SVN::Pool subPool(pool);
563
653
                                   destinationPath.c_str(),
564
654
                                   pegRevision.revision(),
565
655
                                   revision.revision(), force,
566
 
                                   ignoreExternals, FALSE,
 
656
                                   ignoreExternals, ignoreKeywords,
567
657
                                   depth,
568
658
                                   nativeEOL, ctx,
569
659
                                   subPool.getPool()),
613
703
                         CommitMessage *message, svn_depth_t depth,
614
704
                         bool noIgnore, bool noAutoProps,
615
705
                         bool ignoreUnknownNodeTypes,
616
 
                         RevpropTable &revprops,
 
706
                         PropertyTable &revprops,
617
707
                         ImportFilterCallback *ifCallback,
618
708
                         CommitCallback *commitCallback)
619
709
{
658
748
                      const char *path2, Revision &revision2,
659
749
                      const char *localPath, bool forceDelete, svn_depth_t depth,
660
750
                      bool ignoreMergeinfo, bool diffIgnoreAncestry,
661
 
                      bool dryRun, bool recordOnly)
 
751
                      bool dryRun, bool allowMixedRev, bool recordOnly)
662
752
{
663
753
    SVN::Pool subPool(pool);
664
754
    SVN_JNI_NULL_PTR_EX(path1, "path1", );
683
773
                                  depth,
684
774
                                  ignoreMergeinfo, diffIgnoreAncestry,
685
775
                                  forceDelete, recordOnly, dryRun,
686
 
                                  TRUE, NULL, ctx, subPool.getPool()), );
 
776
                                  allowMixedRev, NULL, ctx,
 
777
                                  subPool.getPool()), );
687
778
}
688
779
 
689
780
void SVNClient::merge(const char *path, Revision &pegRevision,
690
781
                      std::vector<RevisionRange> *rangesToMerge,
691
782
                      const char *localPath, bool forceDelete, svn_depth_t depth,
692
783
                      bool ignoreMergeinfo, bool diffIgnoreAncestry,
693
 
                      bool dryRun, bool recordOnly)
 
784
                      bool dryRun, bool allowMixedRev, bool recordOnly)
694
785
{
695
786
    SVN::Pool subPool(pool);
696
787
    SVN_JNI_NULL_PTR_EX(path, "path", );
718
809
                                      depth,
719
810
                                      ignoreMergeinfo, diffIgnoreAncestry,
720
811
                                      forceDelete, recordOnly,
721
 
                                      dryRun, TRUE, NULL, ctx,
 
812
                                      dryRun, allowMixedRev, NULL, ctx,
722
813
                                      subPool.getPool()), );
723
814
}
724
815
 
725
 
void SVNClient::mergeReintegrate(const char *path, Revision &pegRevision,
726
 
                                 const char *localPath, bool dryRun)
727
 
{
728
 
    SVN::Pool subPool(pool);
729
 
    SVN_JNI_NULL_PTR_EX(path, "path", );
730
 
    SVN_JNI_NULL_PTR_EX(localPath, "localPath", );
731
 
    Path intLocalPath(localPath, subPool);
732
 
    SVN_JNI_ERR(intLocalPath.error_occurred(), );
733
 
 
734
 
    Path srcPath(path, subPool);
735
 
    SVN_JNI_ERR(srcPath.error_occurred(), );
736
 
 
737
 
    svn_client_ctx_t *ctx = context.getContext(NULL, subPool);
738
 
    if (ctx == NULL)
739
 
        return;
740
 
 
741
 
    SVN_JNI_ERR(svn_client_merge_reintegrate(srcPath.c_str(),
742
 
                                             pegRevision.revision(),
743
 
                                             intLocalPath.c_str(),
744
 
                                             dryRun, NULL, ctx,
745
 
                                             subPool.getPool()), );
746
 
}
 
816
/* SVNClient::mergeReintegrate is implemented in deprecated.cpp. */
747
817
 
748
818
jobject
749
819
SVNClient::getMergeinfo(const char *target, Revision &pegRevision)
750
820
{
751
821
    SVN::Pool subPool(pool);
752
 
    JNIEnv *env = JNIUtil::getEnv();
753
 
 
754
822
    svn_client_ctx_t *ctx = context.getContext(NULL, subPool);
755
823
    if (ctx == NULL)
756
824
        return NULL;
765
833
                NULL);
766
834
    if (mergeinfo == NULL)
767
835
        return NULL;
768
 
 
769
 
    // Transform mergeinfo into Java Mergeinfo object.
770
 
    jclass clazz = env->FindClass(JAVA_PACKAGE "/types/Mergeinfo");
771
 
    if (JNIUtil::isJavaExceptionThrown())
772
 
        return NULL;
773
 
 
774
 
    static jmethodID ctor = 0;
775
 
    if (ctor == 0)
776
 
    {
777
 
        ctor = env->GetMethodID(clazz, "<init>", "()V");
778
 
        if (JNIUtil::isJavaExceptionThrown())
779
 
            return NULL;
780
 
    }
781
 
 
782
 
    static jmethodID addRevisions = 0;
783
 
    if (addRevisions == 0)
784
 
    {
785
 
        addRevisions = env->GetMethodID(clazz, "addRevisions",
786
 
                                        "(Ljava/lang/String;"
787
 
                                        "Ljava/util/List;)V");
788
 
        if (JNIUtil::isJavaExceptionThrown())
789
 
            return NULL;
790
 
    }
791
 
 
792
 
    jobject jmergeinfo = env->NewObject(clazz, ctor);
793
 
    if (JNIUtil::isJavaExceptionThrown())
794
 
        return NULL;
795
 
 
796
 
    apr_hash_index_t *hi;
797
 
    for (hi = apr_hash_first(subPool.getPool(), mergeinfo);
798
 
         hi;
799
 
         hi = apr_hash_next(hi))
800
 
    {
801
 
        const void *path;
802
 
        void *val;
803
 
        apr_hash_this(hi, &path, NULL, &val);
804
 
 
805
 
        jstring jpath =
806
 
            JNIUtil::makeJString(reinterpret_cast<const char *>(path));
807
 
        jobject jranges =
808
 
            CreateJ::RevisionRangeList(reinterpret_cast<svn_rangelist_t *>(val));
809
 
 
810
 
        env->CallVoidMethod(jmergeinfo, addRevisions, jpath, jranges);
811
 
 
812
 
        env->DeleteLocalRef(jranges);
813
 
        env->DeleteLocalRef(jpath);
814
 
    }
815
 
 
816
 
    env->DeleteLocalRef(clazz);
817
 
 
818
 
    return jmergeinfo;
 
836
    return CreateJ::Mergeinfo(mergeinfo, subPool.getPool());
819
837
}
820
838
 
821
839
void SVNClient::getMergeinfoLog(int type, const char *pathOrURL,
954
972
                                  const char *name,
955
973
                                  CommitMessage *message,
956
974
                                  JNIByteArray &value, bool force,
957
 
                                  RevpropTable &revprops,
 
975
                                  PropertyTable &revprops,
958
976
                                  CommitCallback *callback)
959
977
{
960
978
    SVN::Pool subPool(pool);
1155
1173
                                               subPool.getPool()), );
1156
1174
}
1157
1175
 
1158
 
void SVNClient::streamFileContent(const char *path, Revision &revision,
1159
 
                                  Revision &pegRevision,
1160
 
                                  OutputStream &outputStream)
 
1176
apr_hash_t *SVNClient::streamFileContent(const char *path,
 
1177
                                         Revision &revision,
 
1178
                                         Revision &pegRevision,
 
1179
                                         bool expand_keywords,
 
1180
                                         bool return_props,
 
1181
                                         OutputStream &outputStream)
1161
1182
{
1162
1183
    SVN::Pool subPool(pool);
1163
 
    SVN_JNI_NULL_PTR_EX(path, "path", );
 
1184
    SVN_JNI_NULL_PTR_EX(path, "path", NULL);
1164
1185
    Path intPath(path, subPool);
1165
 
    SVN_JNI_ERR(intPath.error_occurred(), );
 
1186
    SVN_JNI_ERR(intPath.error_occurred(), NULL);
1166
1187
 
1167
1188
    svn_client_ctx_t *ctx = context.getContext(NULL, subPool);
1168
1189
    if (ctx == NULL)
1169
 
        return;
 
1190
        return NULL;
1170
1191
 
1171
 
    SVN_JNI_ERR(svn_client_cat2(outputStream.getStream(subPool),
1172
 
                                intPath.c_str(), pegRevision.revision(),
1173
 
                                revision.revision(), ctx, subPool.getPool()),
1174
 
                );
 
1192
    apr_hash_t *props = NULL;
 
1193
    SVN_JNI_ERR(svn_client_cat3((return_props ? &props : NULL),
 
1194
                                outputStream.getStream(subPool),
 
1195
                                intPath.c_str(),
 
1196
                                pegRevision.revision(), revision.revision(),
 
1197
                                expand_keywords, ctx,
 
1198
                                subPool.getPool(), subPool.getPool()),
 
1199
        NULL);
 
1200
    return props;
1175
1201
}
1176
1202
 
1177
1203
jbyteArray SVNClient::revProperty(const char *path,
1239
1265
void SVNClient::blame(const char *path, Revision &pegRevision,
1240
1266
                      Revision &revisionStart, Revision &revisionEnd,
1241
1267
                      bool ignoreMimeType, bool includeMergedRevisions,
1242
 
                      BlameCallback *callback)
 
1268
                      BlameCallback *callback, DiffOptions const& options)
1243
1269
{
1244
1270
    SVN::Pool subPool(pool);
1245
1271
    SVN_JNI_NULL_PTR_EX(path, "path", );
1253
1279
    SVN_JNI_ERR(svn_client_blame5(
1254
1280
          intPath.c_str(), pegRevision.revision(), revisionStart.revision(),
1255
1281
          revisionEnd.revision(),
1256
 
          svn_diff_file_options_create(subPool.getPool()), ignoreMimeType,
 
1282
          options.fileOptions(subPool), ignoreMimeType,
1257
1283
          includeMergedRevisions, BlameCallback::callback, callback, ctx,
1258
1284
          subPool.getPool()),
1259
1285
        );
1288
1314
}
1289
1315
 
1290
1316
void SVNClient::getChangelists(const char *rootPath,
1291
 
                               StringArray &changelists,
 
1317
                               StringArray *changelists,
1292
1318
                               svn_depth_t depth,
1293
1319
                               ChangelistCallback *callback)
1294
1320
{
1295
1321
    SVN::Pool subPool(pool);
1296
1322
    svn_client_ctx_t *ctx = context.getContext(NULL, subPool);
1297
1323
 
1298
 
    SVN_JNI_ERR(svn_client_get_changelists(rootPath,
1299
 
                                           changelists.array(subPool),
 
1324
    const apr_array_header_t *cl_array = (!changelists ? NULL
 
1325
                                          : changelists->array(subPool));
 
1326
 
 
1327
    SVN_JNI_ERR(svn_client_get_changelists(rootPath, cl_array,
1300
1328
                                           depth, ChangelistCallback::callback,
1301
1329
                                           callback, ctx, subPool.getPool()),
1302
1330
                );
1392
1420
        }
1393
1421
        else
1394
1422
        {
1395
 
            char *message = JNIUtil::getFormatBuffer();
1396
 
            apr_snprintf(message, JNIUtil::formatBufferSize,
 
1423
            char buffer[2048];
 
1424
            apr_snprintf(buffer, sizeof(buffer),
1397
1425
                         _("'%s' not versioned, and not exported\n"), path);
1398
 
            return JNIUtil::makeJString(message);
 
1426
            return JNIUtil::makeJString(buffer);
1399
1427
        }
1400
1428
    }
1401
1429
 
1465
1493
                                        &set_rev, ctx, subPool.getPool()),
1466
1494
                NULL);
1467
1495
 
1468
 
    return CreateJ::PropertyMap(props);
 
1496
    return CreateJ::PropertyMap(props, subPool.getPool());
1469
1497
}
1470
1498
 
1471
 
struct info_baton
1472
 
{
1473
 
    std::vector<info_entry> infoVect;
1474
 
    apr_pool_t *pool;
1475
 
};
1476
 
 
1477
1499
void
1478
 
SVNClient::info2(const char *path, Revision &revision, Revision &pegRevision,
1479
 
                 svn_depth_t depth, StringArray &changelists,
1480
 
                 InfoCallback *callback)
 
1500
SVNClient::info(const char *path,
 
1501
                Revision &revision, Revision &pegRevision, svn_depth_t depth,
 
1502
                svn_boolean_t fetchExcluded, svn_boolean_t fetchActualOnly,
 
1503
                svn_boolean_t includeExternals,
 
1504
                 StringArray &changelists, InfoCallback *callback)
1481
1505
{
1482
1506
    SVN_JNI_NULL_PTR_EX(path, "path", );
1483
1507
 
1489
1513
    Path checkedPath(path, subPool);
1490
1514
    SVN_JNI_ERR(checkedPath.error_occurred(), );
1491
1515
 
1492
 
    SVN_JNI_ERR(svn_client_info3(checkedPath.c_str(),
 
1516
    SVN_JNI_ERR(svn_client_info4(checkedPath.c_str(),
1493
1517
                                 pegRevision.revision(),
1494
 
                                 revision.revision(),
1495
 
                                 depth, FALSE, TRUE,
 
1518
                                 revision.revision(), depth,
 
1519
                                 fetchExcluded, fetchActualOnly,
 
1520
                                 includeExternals,
1496
1521
                                 changelists.array(subPool),
1497
1522
                                 InfoCallback::callback, callback,
1498
1523
                                 ctx, subPool.getPool()), );
1525
1550
                                 ctx, subPool.getPool()), );
1526
1551
}
1527
1552
 
 
1553
void SVNClient::vacuum(const char *path,
 
1554
                       bool remove_unversioned_items,
 
1555
                       bool remove_ignored_items,
 
1556
                       bool fix_recorded_timestamps,
 
1557
                       bool remove_unused_pristines,
 
1558
                       bool include_externals)
 
1559
{
 
1560
    SVN_JNI_NULL_PTR_EX(path, "path", );
 
1561
 
 
1562
    SVN::Pool subPool(pool);
 
1563
    svn_client_ctx_t *ctx = context.getContext(NULL, subPool);
 
1564
    if (ctx == NULL)
 
1565
        return;
 
1566
 
 
1567
    SVN_JNI_ERR(svn_client_vacuum(path,
 
1568
                                  remove_unversioned_items,
 
1569
                                  remove_ignored_items,
 
1570
                                  fix_recorded_timestamps,
 
1571
                                  remove_unused_pristines,
 
1572
                                  include_externals,
 
1573
                                  ctx, subPool.getPool()), );
 
1574
}
 
1575
 
 
1576
jobject
 
1577
SVNClient::openRemoteSession(const char* path, int retryAttempts)
 
1578
{
 
1579
    static const svn_opt_revision_t HEAD = { svn_opt_revision_head, {0}};
 
1580
    static const svn_opt_revision_t NONE = { svn_opt_revision_unspecified, {0}};
 
1581
 
 
1582
    SVN_JNI_NULL_PTR_EX(path, "path", NULL);
 
1583
 
 
1584
    SVN::Pool subPool(pool);
 
1585
    svn_client_ctx_t *ctx = context.getContext(NULL, subPool);
 
1586
    if (ctx == NULL)
 
1587
        return NULL;
 
1588
 
 
1589
    Path checkedPath(path, subPool);
 
1590
    SVN_JNI_ERR(checkedPath.error_occurred(), NULL);
 
1591
 
 
1592
    struct PathInfo
 
1593
    {
 
1594
        std::string url;
 
1595
        std::string uuid;
 
1596
        static svn_error_t *callback(void *baton,
 
1597
                                     const char *,
 
1598
                                     const svn_client_info2_t *info,
 
1599
                                     apr_pool_t *)
 
1600
          {
 
1601
              PathInfo* const pi = static_cast<PathInfo*>(baton);
 
1602
              pi->url = info->URL;
 
1603
              pi->uuid = info->repos_UUID;
 
1604
              return SVN_NO_ERROR;
 
1605
          }
 
1606
    } path_info;
 
1607
 
 
1608
    SVN_JNI_ERR(svn_client_info4(
 
1609
                    checkedPath.c_str(), &NONE,
 
1610
                    (svn_path_is_url(checkedPath.c_str()) ? &HEAD : &NONE),
 
1611
                    svn_depth_empty, FALSE, TRUE, FALSE, NULL,
 
1612
                    PathInfo::callback, &path_info,
 
1613
                    ctx, subPool.getPool()),
 
1614
                NULL);
 
1615
 
 
1616
    /* Decouple the RemoteSession's context from SVNClient's context
 
1617
       by creating a copy of the prompter here. */
 
1618
 
 
1619
    jobject jremoteSession = RemoteSession::open(
 
1620
        retryAttempts, path_info.url.c_str(), path_info.uuid.c_str(),
 
1621
        context.getConfigDirectory(),
 
1622
        context.getUsername(), context.getPassword(),
 
1623
        context.clonePrompter(), context.getSelf(),
 
1624
        context.getConfigEventHandler(), context.getTunnelCallback());
 
1625
    if (JNIUtil::isJavaExceptionThrown())
 
1626
      jremoteSession = NULL;
 
1627
 
 
1628
    return jremoteSession;
 
1629
}
 
1630
 
1528
1631
ClientContext &
1529
1632
SVNClient::getClientContext()
1530
1633
{