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

« back to all changes in this revision

Viewing changes to subversion/bindings/javahl/native/RemoteSession.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:
 
1
/**
 
2
 * @copyright
 
3
 * ====================================================================
 
4
 *    Licensed to the Apache Software Foundation (ASF) under one
 
5
 *    or more contributor license agreements.  See the NOTICE file
 
6
 *    distributed with this work for additional information
 
7
 *    regarding copyright ownership.  The ASF licenses this file
 
8
 *    to you under the Apache License, Version 2.0 (the
 
9
 *    "License"); you may not use this file except in compliance
 
10
 *    with the License.  You may obtain a copy of the License at
 
11
 *
 
12
 *      http://www.apache.org/licenses/LICENSE-2.0
 
13
 *
 
14
 *    Unless required by applicable law or agreed to in writing,
 
15
 *    software distributed under the License is distributed on an
 
16
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 
17
 *    KIND, either express or implied.  See the License for the
 
18
 *    specific language governing permissions and limitations
 
19
 *    under the License.
 
20
 * ====================================================================
 
21
 * @endcopyright
 
22
 *
 
23
 * @file RemoteSession.cpp
 
24
 * @brief Implementation of the class RemoteSession
 
25
 */
 
26
 
 
27
#include <cstring>
 
28
#include <memory>
 
29
#include <set>
 
30
 
 
31
#include "JNIByteArray.h"
 
32
#include "JNIStringHolder.h"
 
33
#include "JNIUtil.h"
 
34
#include "Path.h"
 
35
 
 
36
#include "svn_ra.h"
 
37
#include "svn_string.h"
 
38
#include "svn_dirent_uri.h"
 
39
#include "svn_delta.h"
 
40
 
 
41
#include "CreateJ.h"
 
42
#include "EnumMapper.h"
 
43
#include "Iterator.h"
 
44
#include "LogMessageCallback.h"
 
45
#include "OutputStream.h"
 
46
#include "Prompter.h"
 
47
#include "Revision.h"
 
48
#include "RemoteSession.h"
 
49
#include "EditorProxy.h"
 
50
#include "StateReporter.h"
 
51
 
 
52
#include <apr_strings.h>
 
53
#include "svn_private_config.h"
 
54
 
 
55
#define JAVA_CLASS_REMOTE_SESSION JAVAHL_CLASS("/remote/RemoteSession")
 
56
 
 
57
RemoteSession *
 
58
RemoteSession::getCppObject(jobject jthis)
 
59
{
 
60
  static jfieldID fid = 0;
 
61
  jlong cppAddr = SVNBase::findCppAddrForJObject(jthis, &fid,
 
62
      JAVA_CLASS_REMOTE_SESSION);
 
63
  return (cppAddr == 0 ? NULL : reinterpret_cast<RemoteSession *>(cppAddr));
 
64
}
 
65
 
 
66
jobject
 
67
RemoteSession::open(jint jretryAttempts,
 
68
                    jstring jurl, jstring juuid,
 
69
                    jstring jconfigDirectory,
 
70
                    jstring jusername, jstring jpassword,
 
71
                    jobject jprompter, jobject jdeprecatedPrompter,
 
72
                    jobject jprogress, jobject jcfgcb, jobject jtunnelcb)
 
73
{
 
74
  SVN_ERR_ASSERT_NO_RETURN(!(jprompter && jdeprecatedPrompter));
 
75
 
 
76
  SVN::Pool requestPool;
 
77
  URL url(jurl, requestPool);
 
78
  if (JNIUtil::isExceptionThrown())
 
79
    return NULL;
 
80
  SVN_JNI_ERR(url.error_occurred(), NULL);
 
81
 
 
82
  JNIStringHolder uuid(juuid);
 
83
  if (JNIUtil::isExceptionThrown())
 
84
    return NULL;
 
85
 
 
86
  Path configDirectory(jconfigDirectory, requestPool);
 
87
  if (JNIUtil::isExceptionThrown())
 
88
    return NULL;
 
89
  SVN_JNI_ERR(configDirectory.error_occurred(), NULL);
 
90
 
 
91
  JNIStringHolder usernameStr(jusername);
 
92
  if (JNIUtil::isExceptionThrown())
 
93
    return NULL;
 
94
 
 
95
  JNIStringHolder passwordStr(jpassword);
 
96
  if (JNIUtil::isExceptionThrown())
 
97
    return NULL;
 
98
 
 
99
  Prompter::UniquePtr prompter(jprompter ? Prompter::create(jprompter)
 
100
                               : CompatPrompter::create(jdeprecatedPrompter));
 
101
  if (JNIUtil::isExceptionThrown())
 
102
    return NULL;
 
103
 
 
104
  jobject jremoteSession = open(
 
105
      jretryAttempts, url.c_str(), uuid,
 
106
      (jconfigDirectory ? configDirectory.c_str() : NULL),
 
107
      usernameStr, passwordStr, prompter, jprogress, jcfgcb, jtunnelcb);
 
108
  if (JNIUtil::isExceptionThrown() || !jremoteSession)
 
109
    jremoteSession = NULL;
 
110
  return jremoteSession;
 
111
}
 
112
 
 
113
jobject
 
114
RemoteSession::open(jint jretryAttempts,
 
115
                    const char* url, const char* uuid,
 
116
                    const char* configDirectory,
 
117
                    const char*  usernameStr, const char*  passwordStr,
 
118
                    Prompter::UniquePtr prompter, jobject jprogress,
 
119
                    jobject jcfgcb, jobject jtunnelcb)
 
120
{
 
121
  RemoteSession* session = new RemoteSession(
 
122
      jretryAttempts, url, uuid, configDirectory,
 
123
      usernameStr, passwordStr, prompter, jcfgcb, jtunnelcb);
 
124
  if (JNIUtil::isJavaExceptionThrown() || !session)
 
125
    {
 
126
      delete session;
 
127
      return NULL;
 
128
    }
 
129
 
 
130
  // Create java session object
 
131
  JNIEnv *env = JNIUtil::getEnv();
 
132
 
 
133
  jclass clazz = env->FindClass(JAVA_CLASS_REMOTE_SESSION);
 
134
  if (JNIUtil::isJavaExceptionThrown())
 
135
    {
 
136
      delete session;
 
137
      return NULL;
 
138
    }
 
139
 
 
140
  static jmethodID ctor = 0;
 
141
  if (ctor == 0)
 
142
    {
 
143
      ctor = env->GetMethodID(clazz, "<init>", "(J)V");
 
144
      if (JNIUtil::isJavaExceptionThrown())
 
145
        {
 
146
          delete session;
 
147
          return NULL;
 
148
        }
 
149
    }
 
150
 
 
151
  jobject jremoteSession = env->NewObject(clazz, ctor, session->getCppAddr());
 
152
  if (JNIUtil::isJavaExceptionThrown())
 
153
    {
 
154
      delete session;
 
155
      return NULL;
 
156
    }
 
157
 
 
158
  session->m_context->activate(jremoteSession, jprogress);
 
159
  if (JNIUtil::isJavaExceptionThrown())
 
160
    {
 
161
      delete session;
 
162
      jremoteSession = NULL;
 
163
    }
 
164
 
 
165
  return jremoteSession;
 
166
}
 
167
 
 
168
 
 
169
namespace{
 
170
  struct compare_c_strings
 
171
  {
 
172
    bool operator()(const char* a, const char* b)
 
173
      {
 
174
        return (0 < std::strcmp(a, b));
 
175
      }
 
176
  };
 
177
  typedef std::set<const char*, compare_c_strings> attempt_set;
 
178
  typedef std::pair<attempt_set::iterator, bool> attempt_insert;
 
179
} // anonymous namespace
 
180
 
 
181
RemoteSession::RemoteSession(int retryAttempts,
 
182
                             const char* url, const char* uuid,
 
183
                             const char* configDirectory,
 
184
                             const char*  username, const char*  password,
 
185
                             Prompter::UniquePtr prompter,
 
186
                             jobject jcfgcb, jobject jtunnelcb)
 
187
  : m_session(NULL), m_context(NULL)
 
188
{
 
189
  m_context = new RemoteSessionContext(
 
190
      pool, configDirectory, username, password, prompter, jcfgcb, jtunnelcb);
 
191
  if (JNIUtil::isJavaExceptionThrown())
 
192
    return;
 
193
 
 
194
  const char* corrected_url = NULL;
 
195
  bool cycle_detected = false;
 
196
  attempt_set attempted;
 
197
 
 
198
  while (retryAttempts-- >= 0)
 
199
    {
 
200
      SVN_JNI_ERR(
 
201
          svn_ra_open4(&m_session, &corrected_url,
 
202
                       url, uuid, m_context->getCallbacks(),
 
203
                       m_context->getCallbackBaton(),
 
204
                       m_context->getConfigData(),
 
205
                       pool.getPool()),
 
206
                  );
 
207
 
 
208
      if (!corrected_url)
 
209
        break;
 
210
 
 
211
      attempt_insert result = attempted.insert(corrected_url);
 
212
      if (!result.second)
 
213
        {
 
214
          cycle_detected = true;
 
215
          break;
 
216
        }
 
217
    }
 
218
 
 
219
  if (cycle_detected)
 
220
    {
 
221
      JNIEnv *env = JNIUtil::getEnv();
 
222
 
 
223
      jstring exmsg = JNIUtil::makeJString(
 
224
          apr_psprintf(pool.getPool(),
 
225
                       _("Redirect cycle detected for URL '%s'"),
 
226
                       corrected_url));
 
227
 
 
228
      jclass excls = env->FindClass(
 
229
          JAVAHL_CLASS("/SubversionException"));
 
230
      if (JNIUtil::isJavaExceptionThrown())
 
231
        return;
 
232
 
 
233
      static jmethodID exctor = 0;
 
234
      if (exctor == 0)
 
235
        {
 
236
          exctor = env->GetMethodID(excls, "<init>", "(Ljava/lang/String;)V");
 
237
          if (JNIUtil::isJavaExceptionThrown())
 
238
            return;
 
239
        }
 
240
 
 
241
      jobject ex = env->NewObject(excls, exctor, exmsg);
 
242
      env->Throw(static_cast<jthrowable>(ex));
 
243
      return;
 
244
    }
 
245
 
 
246
  if (corrected_url)
 
247
    {
 
248
      JNIEnv *env = JNIUtil::getEnv();
 
249
 
 
250
      jstring exmsg = JNIUtil::makeJString(_("Too many redirects"));
 
251
      if (JNIUtil::isJavaExceptionThrown())
 
252
        return;
 
253
 
 
254
      jstring exurl = JNIUtil::makeJString(corrected_url);
 
255
      if (JNIUtil::isJavaExceptionThrown())
 
256
        return;
 
257
 
 
258
      jclass excls = env->FindClass(
 
259
          JAVAHL_CLASS("/remote/RetryOpenSession"));
 
260
      if (JNIUtil::isJavaExceptionThrown())
 
261
        return;
 
262
 
 
263
      static jmethodID exctor = 0;
 
264
      if (exctor == 0)
 
265
        {
 
266
          exctor = env->GetMethodID(excls, "<init>", "(JJ)V");
 
267
          if (JNIUtil::isJavaExceptionThrown())
 
268
            return;
 
269
        }
 
270
 
 
271
      jobject ex = env->NewObject(excls, exctor, exmsg, exurl);
 
272
      env->Throw(static_cast<jthrowable>(ex));
 
273
      return;
 
274
    }
 
275
}
 
276
 
 
277
RemoteSession::~RemoteSession()
 
278
{
 
279
  delete m_context;
 
280
}
 
281
 
 
282
void
 
283
RemoteSession::dispose(jobject jthis)
 
284
{
 
285
  static jfieldID fid = 0;
 
286
  SVNBase::dispose(jthis, &fid, JAVA_CLASS_REMOTE_SESSION);
 
287
}
 
288
 
 
289
void RemoteSession::reparent(jstring jurl)
 
290
{
 
291
  SVN::Pool subPool(pool);
 
292
  URL url(jurl, subPool);
 
293
  if (JNIUtil::isExceptionThrown())
 
294
    return;
 
295
  SVN_JNI_ERR(url.error_occurred(),);
 
296
 
 
297
  SVN_JNI_ERR(svn_ra_reparent(m_session, url.c_str(), subPool.getPool()), );
 
298
}
 
299
 
 
300
jstring
 
301
RemoteSession::getSessionUrl()
 
302
{
 
303
  SVN::Pool subPool(pool);
 
304
  const char* url;
 
305
  SVN_JNI_ERR(svn_ra_get_session_url(m_session, &url, subPool.getPool()), NULL);
 
306
 
 
307
  jstring jurl = JNIUtil::makeJString(url);
 
308
  if (JNIUtil::isJavaExceptionThrown())
 
309
    return NULL;
 
310
 
 
311
  return jurl;
 
312
}
 
313
 
 
314
jstring
 
315
RemoteSession::getSessionRelativePath(jstring jurl)
 
316
{
 
317
  SVN::Pool subPool(pool);
 
318
  URL url(jurl, subPool);
 
319
  if (JNIUtil::isExceptionThrown())
 
320
    return NULL;
 
321
  SVN_JNI_ERR(url.error_occurred(), NULL);
 
322
 
 
323
  const char* rel_path;
 
324
  SVN_JNI_ERR(svn_ra_get_path_relative_to_session(
 
325
                  m_session, &rel_path, url.c_str(), subPool.getPool()),
 
326
              NULL);
 
327
  jstring jrel_path = JNIUtil::makeJString(rel_path);
 
328
  if (JNIUtil::isJavaExceptionThrown())
 
329
    return NULL;
 
330
 
 
331
  return jrel_path;
 
332
}
 
333
 
 
334
jstring
 
335
RemoteSession::getReposRelativePath(jstring jurl)
 
336
{
 
337
  SVN::Pool subPool(pool);
 
338
  URL url(jurl, subPool);
 
339
  if (JNIUtil::isExceptionThrown())
 
340
    return NULL;
 
341
  SVN_JNI_ERR(url.error_occurred(), NULL);
 
342
 
 
343
  const char* rel_path;
 
344
  SVN_JNI_ERR(svn_ra_get_path_relative_to_root(m_session, &rel_path,
 
345
                                               url.c_str(),
 
346
                                               subPool.getPool()),
 
347
              NULL);
 
348
 
 
349
  jstring jrel_path = JNIUtil::makeJString(rel_path);
 
350
  if (JNIUtil::isJavaExceptionThrown())
 
351
    return NULL;
 
352
 
 
353
  return jrel_path;
 
354
}
 
355
 
 
356
jstring
 
357
RemoteSession::getReposUUID()
 
358
{
 
359
  SVN::Pool subPool(pool);
 
360
  const char * uuid;
 
361
  SVN_JNI_ERR(svn_ra_get_uuid2(m_session, &uuid, subPool.getPool()), NULL);
 
362
 
 
363
  jstring juuid = JNIUtil::makeJString(uuid);
 
364
  if (JNIUtil::isJavaExceptionThrown())
 
365
    return NULL;
 
366
 
 
367
  return juuid;
 
368
}
 
369
 
 
370
jstring
 
371
RemoteSession::getReposRootUrl()
 
372
{
 
373
  SVN::Pool subPool(pool);
 
374
  const char* url;
 
375
  SVN_JNI_ERR(svn_ra_get_repos_root2(m_session, &url, subPool.getPool()),
 
376
              NULL);
 
377
 
 
378
  jstring jurl = JNIUtil::makeJString(url);
 
379
  if (JNIUtil::isJavaExceptionThrown())
 
380
    return NULL;
 
381
 
 
382
  return jurl;
 
383
}
 
384
 
 
385
jlong
 
386
RemoteSession::getLatestRevision()
 
387
{
 
388
  SVN::Pool subPool(pool);
 
389
  svn_revnum_t rev;
 
390
  SVN_JNI_ERR(svn_ra_get_latest_revnum(m_session, &rev, subPool.getPool()),
 
391
              SVN_INVALID_REVNUM);
 
392
  return rev;
 
393
}
 
394
 
 
395
jlong
 
396
RemoteSession::getRevisionByTimestamp(jlong timestamp)
 
397
{
 
398
  SVN::Pool subPool(pool);
 
399
  svn_revnum_t rev;
 
400
  SVN_JNI_ERR(svn_ra_get_dated_revision(m_session, &rev,
 
401
                                        apr_time_t(timestamp),
 
402
                                        subPool.getPool()),
 
403
              SVN_INVALID_REVNUM);
 
404
  return rev;
 
405
}
 
406
 
 
407
namespace {
 
408
svn_string_t*
 
409
byte_array_to_svn_string(JNIByteArray& ary, SVN::Pool& scratch_pool)
 
410
{
 
411
  if (ary.isNull())
 
412
    return NULL;
 
413
  return svn_string_ncreate(reinterpret_cast<const char*>(ary.getBytes()),
 
414
                            ary.getLength(), scratch_pool.getPool());
 
415
}
 
416
} // anonymous namespace
 
417
 
 
418
void
 
419
RemoteSession::changeRevisionProperty(
 
420
    jlong jrevision, jstring jname,
 
421
    jbyteArray jold_value, jbyteArray jvalue)
 
422
{
 
423
  JNIStringHolder name(jname);
 
424
  if (JNIUtil::isExceptionThrown())
 
425
    return;
 
426
 
 
427
  JNIByteArray old_value(jold_value);
 
428
  if (JNIUtil::isExceptionThrown())
 
429
    return;
 
430
 
 
431
  JNIByteArray value(jvalue);
 
432
  if (JNIUtil::isExceptionThrown())
 
433
    return;
 
434
 
 
435
  SVN::Pool subPool(pool);
 
436
  svn_string_t* const* p_old_value = NULL;
 
437
  svn_string_t* const str_old_value =
 
438
    byte_array_to_svn_string(old_value, subPool);
 
439
  if (str_old_value)
 
440
    p_old_value = &str_old_value;
 
441
 
 
442
  SVN_JNI_ERR(svn_ra_change_rev_prop2(m_session,
 
443
                                      svn_revnum_t(jrevision),
 
444
                                      name, p_old_value,
 
445
                                      byte_array_to_svn_string(value, subPool),
 
446
                                      subPool.getPool()), );
 
447
}
 
448
 
 
449
jobject
 
450
RemoteSession::getRevisionProperties(jlong jrevision)
 
451
{
 
452
  SVN::Pool subPool(pool);
 
453
  apr_hash_t *props;
 
454
  SVN_JNI_ERR(svn_ra_rev_proplist(m_session, svn_revnum_t(jrevision),
 
455
                                  &props, subPool.getPool()),
 
456
              NULL);
 
457
 
 
458
  return CreateJ::PropertyMap(props, subPool.getPool());
 
459
}
 
460
 
 
461
jbyteArray
 
462
RemoteSession::getRevisionProperty(jlong jrevision, jstring jname)
 
463
{
 
464
  JNIStringHolder name(jname);
 
465
  if (JNIUtil::isExceptionThrown())
 
466
    return NULL;
 
467
 
 
468
  SVN::Pool subPool(pool);
 
469
  svn_string_t *propval;
 
470
  SVN_JNI_ERR(svn_ra_rev_prop(m_session, svn_revnum_t(jrevision),
 
471
                              name, &propval, subPool.getPool()),
 
472
              NULL);
 
473
 
 
474
  return JNIUtil::makeJByteArray(propval);
 
475
}
 
476
 
 
477
jlong
 
478
RemoteSession::getFile(jlong jrevision, jstring jpath,
 
479
                       jobject jcontents, jobject jproperties)
 
480
{
 
481
  OutputStream contents_proxy(jcontents);
 
482
  if (JNIUtil::isExceptionThrown())
 
483
    return SVN_INVALID_REVNUM;
 
484
 
 
485
  SVN::Pool subPool(pool);
 
486
  Relpath path(jpath, subPool);
 
487
  if (JNIUtil::isExceptionThrown())
 
488
    return SVN_INVALID_REVNUM;
 
489
  SVN_JNI_ERR(path.error_occurred(), SVN_INVALID_REVNUM);
 
490
 
 
491
  apr_hash_t* props = NULL;
 
492
  svn_revnum_t fetched_rev = svn_revnum_t(jrevision);
 
493
  svn_stream_t* contents = (!jcontents ? NULL
 
494
                            : contents_proxy.getStream(subPool));
 
495
 
 
496
  SVN_JNI_ERR(svn_ra_get_file(m_session, path.c_str(), fetched_rev,
 
497
                              contents, &fetched_rev,
 
498
                              (jproperties ? &props : NULL),
 
499
                              subPool.getPool()),
 
500
              SVN_INVALID_REVNUM);
 
501
 
 
502
  if (jproperties)
 
503
    {
 
504
      CreateJ::FillPropertyMap(jproperties, props, subPool.getPool());
 
505
      if (JNIUtil::isExceptionThrown())
 
506
        return SVN_INVALID_REVNUM;
 
507
    }
 
508
 
 
509
  return fetched_rev;
 
510
}
 
511
 
 
512
namespace {
 
513
void fill_dirents(const char* base_url, const char* base_relpath,
 
514
                  jobject jdirents, apr_hash_t* dirents,
 
515
                  apr_pool_t* scratch_pool)
 
516
{
 
517
  if (!dirents)
 
518
    return;
 
519
 
 
520
  base_url = apr_pstrcat(scratch_pool, base_url, "/", base_relpath, NULL);
 
521
  base_url = svn_uri_canonicalize(base_url, scratch_pool);
 
522
  svn_stringbuf_t* abs_path = svn_stringbuf_create(base_url, scratch_pool);
 
523
  svn_stringbuf_appendbyte(abs_path, '/');
 
524
  const apr_size_t base_len = abs_path->len;
 
525
 
 
526
  JNIEnv *env = JNIUtil::getEnv();
 
527
 
 
528
  // Create a local frame for our references
 
529
  env->PushLocalFrame(LOCAL_FRAME_SIZE);
 
530
  if (JNIUtil::isJavaExceptionThrown())
 
531
    return;
 
532
 
 
533
  // We have no way of knowing the exact type of `dirents' in advance
 
534
  // so we cannot remember the "put" method ID across calls.
 
535
  jmethodID put_mid =
 
536
    env->GetMethodID(env->GetObjectClass(jdirents), "put",
 
537
                     "(Ljava/lang/Object;Ljava/lang/Object;)"
 
538
                     "Ljava/lang/Object;");
 
539
  if (JNIUtil::isJavaExceptionThrown())
 
540
    POP_AND_RETURN_NOTHING();
 
541
 
 
542
  static jfieldID path_fid = 0;
 
543
  if (path_fid == 0)
 
544
    {
 
545
      jclass clazz = env->FindClass(JAVAHL_CLASS("/types/DirEntry"));
 
546
      if (JNIUtil::isJavaExceptionThrown())
 
547
        POP_AND_RETURN_NOTHING();
 
548
 
 
549
      path_fid = env->GetFieldID(clazz, "path", "Ljava/lang/String;");
 
550
      if (JNIUtil::isJavaExceptionThrown())
 
551
        POP_AND_RETURN_NOTHING();
 
552
    }
 
553
 
 
554
  for (apr_hash_index_t* hi = apr_hash_first(scratch_pool, dirents);
 
555
       hi; hi = apr_hash_next(hi))
 
556
    {
 
557
      const char* path;
 
558
      svn_dirent_t* dirent;
 
559
 
 
560
      const void *v_key;
 
561
      void *v_val;
 
562
 
 
563
      apr_hash_this(hi, &v_key, NULL, &v_val);
 
564
      path = static_cast<const char*>(v_key);
 
565
      dirent = static_cast<svn_dirent_t*>(v_val);
 
566
      abs_path->len = base_len;
 
567
      svn_stringbuf_appendcstr(abs_path, path);
 
568
 
 
569
      jobject jdirent = CreateJ::DirEntry(path, abs_path->data, dirent);
 
570
      if (JNIUtil::isJavaExceptionThrown())
 
571
        POP_AND_RETURN_NOTHING();
 
572
 
 
573
      // Use the existing DirEntry.path field as the key
 
574
      jstring jpath = jstring(env->GetObjectField(jdirent, path_fid));
 
575
      if (JNIUtil::isJavaExceptionThrown())
 
576
        POP_AND_RETURN_NOTHING();
 
577
 
 
578
      env->CallObjectMethod(jdirents, put_mid, jpath, jdirent);
 
579
      if (JNIUtil::isJavaExceptionThrown())
 
580
        POP_AND_RETURN_NOTHING();
 
581
      env->DeleteLocalRef(jdirent);
 
582
    }
 
583
 
 
584
  POP_AND_RETURN_NOTHING();
 
585
}
 
586
} // anonymous namespace
 
587
 
 
588
jlong
 
589
RemoteSession::getDirectory(jlong jrevision, jstring jpath,
 
590
                            jint jdirent_fields, jobject jdirents,
 
591
                            jobject jproperties)
 
592
{
 
593
  SVN::Pool subPool(pool);
 
594
  Relpath path(jpath, subPool);
 
595
  if (JNIUtil::isExceptionThrown())
 
596
    return SVN_INVALID_REVNUM;
 
597
  SVN_JNI_ERR(path.error_occurred(), SVN_INVALID_REVNUM);
 
598
 
 
599
  apr_hash_t* props = NULL;
 
600
  apr_hash_t* dirents = NULL;
 
601
  svn_revnum_t fetched_rev = svn_revnum_t(jrevision);
 
602
 
 
603
  SVN_JNI_ERR(svn_ra_get_dir2(m_session, (jdirents ? &dirents : NULL),
 
604
                              &fetched_rev, (jproperties ? &props : NULL),
 
605
                              path.c_str(), fetched_rev,
 
606
                              apr_uint32_t(jdirent_fields),
 
607
                              subPool.getPool()),
 
608
              SVN_INVALID_REVNUM);
 
609
 
 
610
  if (jdirents)
 
611
    {
 
612
      // We will construct the absolute path in the DirEntry objects
 
613
      // from the session URL and directory relpath.
 
614
      const char* base_url;
 
615
      SVN_JNI_ERR(svn_ra_get_session_url(m_session, &base_url,
 
616
                                         subPool.getPool()),
 
617
                  SVN_INVALID_REVNUM);
 
618
      fill_dirents(base_url, path.c_str(), jdirents, dirents,
 
619
                   subPool.getPool());
 
620
      if (JNIUtil::isExceptionThrown())
 
621
        return SVN_INVALID_REVNUM;
 
622
    }
 
623
 
 
624
  if (jproperties)
 
625
    {
 
626
      CreateJ::FillPropertyMap(jproperties, props, subPool.getPool());
 
627
      if (JNIUtil::isExceptionThrown())
 
628
        return SVN_INVALID_REVNUM;
 
629
    }
 
630
 
 
631
  return fetched_rev;
 
632
}
 
633
 
 
634
namespace {
 
635
const apr_array_header_t*
 
636
build_string_array(const Iterator& iter,
 
637
                   bool contains_relpaths, SVN::Pool& pool)
 
638
{
 
639
  apr_pool_t* result_pool = pool.getPool();
 
640
  apr_array_header_t* array = apr_array_make(
 
641
      result_pool, 0, sizeof(const char*));
 
642
  while (iter.hasNext())
 
643
    {
 
644
      const char* element;
 
645
      jstring jitem = (jstring)iter.next();
 
646
      if (contains_relpaths)
 
647
        {
 
648
          Relpath item(jitem, pool);
 
649
          if (JNIUtil::isExceptionThrown())
 
650
            return NULL;
 
651
          SVN_JNI_ERR(item.error_occurred(), NULL);
 
652
          element = apr_pstrdup(result_pool, item.c_str());
 
653
        }
 
654
      else
 
655
        {
 
656
          JNIStringHolder item(jitem);
 
657
          if (JNIUtil::isJavaExceptionThrown())
 
658
            return NULL;
 
659
          element = item.pstrdup(result_pool);
 
660
        }
 
661
      APR_ARRAY_PUSH(array, const char*) = element;
 
662
    }
 
663
  return array;
 
664
}
 
665
}
 
666
 
 
667
jobject
 
668
RemoteSession::getMergeinfo(jobject jpaths, jlong jrevision, jobject jinherit,
 
669
                            jboolean jinclude_descendants)
 
670
{
 
671
  Iterator paths_iter(jpaths);
 
672
  if (JNIUtil::isExceptionThrown())
 
673
    return NULL;
 
674
 
 
675
  SVN::Pool subPool(pool);
 
676
  const apr_array_header_t* paths =
 
677
    build_string_array(paths_iter, true, subPool);
 
678
  if (JNIUtil::isJavaExceptionThrown())
 
679
    return NULL;
 
680
 
 
681
  svn_mergeinfo_catalog_t catalog;
 
682
  SVN_JNI_ERR(svn_ra_get_mergeinfo(
 
683
                  m_session, &catalog, paths, svn_revnum_t(jrevision),
 
684
                  EnumMapper::toMergeinfoInheritance(jinherit),
 
685
                  bool(jinclude_descendants),
 
686
                  subPool.getPool()),
 
687
              NULL);
 
688
  if (catalog == NULL)
 
689
    return NULL;
 
690
 
 
691
  JNIEnv* env = JNIUtil::getEnv();
 
692
  jclass cls = env->FindClass("java/util/HashMap");
 
693
  if (JNIUtil::isExceptionThrown())
 
694
    return NULL;
 
695
 
 
696
  static jmethodID ctor_mid = 0;
 
697
  if (0 == ctor_mid)
 
698
    {
 
699
      ctor_mid = env->GetMethodID(cls, "<init>", "()V");
 
700
      if (JNIUtil::isExceptionThrown())
 
701
        return NULL;
 
702
    }
 
703
 
 
704
  static jmethodID put_mid = 0;
 
705
  if (0 == put_mid)
 
706
    {
 
707
      put_mid = env->GetMethodID(cls, "put",
 
708
                                 "(Ljava/lang/Object;"
 
709
                                 "Ljava/lang/Object;)"
 
710
                                 "Ljava/lang/Object;");
 
711
      if (JNIUtil::isExceptionThrown())
 
712
        return NULL;
 
713
    }
 
714
 
 
715
  jobject jcatalog = env->NewObject(cls, ctor_mid);
 
716
  if (JNIUtil::isExceptionThrown())
 
717
    return NULL;
 
718
 
 
719
  for (apr_hash_index_t* hi = apr_hash_first(subPool.getPool(), catalog);
 
720
       hi; hi = apr_hash_next(hi))
 
721
    {
 
722
      const void *v_key;
 
723
      void *v_val;
 
724
      apr_hash_this(hi, &v_key, NULL, &v_val);
 
725
      const char* key = static_cast<const char*>(v_key);
 
726
      svn_mergeinfo_t val = static_cast<svn_mergeinfo_t>(v_val);
 
727
 
 
728
      jstring jpath = JNIUtil::makeJString(key);
 
729
      if (JNIUtil::isExceptionThrown())
 
730
        return NULL;
 
731
      jobject jmergeinfo = CreateJ::Mergeinfo(val, subPool.getPool());
 
732
      if (JNIUtil::isExceptionThrown())
 
733
        return NULL;
 
734
 
 
735
      env->CallObjectMethod(jcatalog, put_mid, jpath, jmergeinfo);
 
736
      if (JNIUtil::isExceptionThrown())
 
737
        return NULL;
 
738
 
 
739
      env->DeleteLocalRef(jpath);
 
740
      env->DeleteLocalRef(jmergeinfo);
 
741
    }
 
742
 
 
743
  return jcatalog;
 
744
}
 
745
 
 
746
// TODO: update
 
747
// TODO: switch
 
748
 
 
749
namespace {
 
750
svn_error_t*
 
751
status_unlock_func(void* baton, const char* path, apr_pool_t* scratch_pool)
 
752
{
 
753
  //DEBUG:fprintf(stderr, "  (n) status_unlock_func('%s')\n", path);
 
754
  return SVN_NO_ERROR;
 
755
}
 
756
 
 
757
svn_error_t*
 
758
status_fetch_props_func(apr_hash_t **props, void *baton,
 
759
                        const char *path, svn_revnum_t base_revision,
 
760
                        apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 
761
{
 
762
  //DEBUG:fprintf(stderr, "  (n) status_fetch_props_func('%s', r%lld)\n",
 
763
  //DEBUG:        path, static_cast<long long>(base_revision));
 
764
  *props = apr_hash_make(result_pool);
 
765
  return SVN_NO_ERROR;
 
766
}
 
767
 
 
768
svn_error_t*
 
769
status_fetch_base_func(const char **filename, void *baton,
 
770
                       const char *path, svn_revnum_t base_revision,
 
771
                       apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 
772
{
 
773
  //DEBUG:fprintf(stderr, "  (n) status_fetch_base_func('%s', r%lld)\n",
 
774
  //DEBUG:        path, static_cast<long long>(base_revision));
 
775
  *filename = NULL;
 
776
  return SVN_NO_ERROR;
 
777
}
 
778
 
 
779
svn_error_t*
 
780
status_start_edit_func(void* baton, svn_revnum_t start_revision)
 
781
{
 
782
  //DEBUG:fprintf(stderr, "  (n) status_start_edit_func(r%lld)\n",
 
783
  //DEBUG:        static_cast<long long>(start_revision));
 
784
  return SVN_NO_ERROR;
 
785
}
 
786
 
 
787
svn_error_t*
 
788
status_target_revision_func(void* baton, svn_revnum_t target_revision,
 
789
                            apr_pool_t* scratch_pool)
 
790
{
 
791
  //DEBUG:fprintf(stderr, "  (n) status_target_revision_func(r%lld)\n",
 
792
  //DEBUG:        static_cast<long long>(target_revision));
 
793
  *static_cast<svn_revnum_t*>(baton) = target_revision;
 
794
  return SVN_NO_ERROR;
 
795
}
 
796
 
 
797
const EditorProxyCallbacks template_status_editor_callbacks = {
 
798
  status_unlock_func,
 
799
  status_fetch_props_func,
 
800
  status_fetch_base_func,
 
801
  { status_start_edit_func, status_target_revision_func, NULL },
 
802
  NULL
 
803
};
 
804
} // anonymous namespace
 
805
 
 
806
void
 
807
RemoteSession::status(jobject jthis, jstring jstatus_target,
 
808
                      jlong jrevision, jobject jdepth,
 
809
                      jobject jstatus_editor, jobject jreporter)
 
810
{
 
811
  StateReporter *rp = StateReporter::getCppObject(jreporter);
 
812
  CPPADDR_NULL_PTR(rp,);
 
813
 
 
814
  SVN::Pool scratchPool(rp->get_report_pool());
 
815
  Relpath status_target(jstatus_target, scratchPool);
 
816
  if (JNIUtil::isExceptionThrown())
 
817
    return;
 
818
 
 
819
  apr_pool_t* scratch_pool = scratchPool.getPool();
 
820
  const char* repos_root_url;
 
821
  SVN_JNI_ERR(svn_ra_get_repos_root2(m_session, &repos_root_url,
 
822
                                     scratch_pool),);
 
823
  const char* session_root_url;
 
824
  SVN_JNI_ERR(svn_ra_get_session_url(m_session, &session_root_url,
 
825
                                     scratch_pool),);
 
826
  const char* base_relpath;
 
827
  SVN_JNI_ERR(svn_ra_get_path_relative_to_root(m_session, &base_relpath,
 
828
                                               session_root_url,
 
829
                                               scratch_pool),);
 
830
 
 
831
  EditorProxyCallbacks proxy_callbacks =
 
832
    template_status_editor_callbacks;
 
833
  proxy_callbacks.m_extra_baton.baton = &rp->m_target_revision;
 
834
 
 
835
  apr_pool_t* report_pool = rp->get_report_pool();
 
836
  std::auto_ptr<EditorProxy> editor(
 
837
      new EditorProxy(jstatus_editor, report_pool,
 
838
                      repos_root_url, base_relpath,
 
839
                      m_context->checkCancel, m_context,
 
840
                      proxy_callbacks));
 
841
  if (JNIUtil::isExceptionThrown())
 
842
    return;
 
843
 
 
844
  const svn_ra_reporter3_t* raw_reporter;
 
845
  void* report_baton;
 
846
  SVN_JNI_ERR(svn_ra_do_status2(m_session,
 
847
                                &raw_reporter, &report_baton,
 
848
                                status_target.c_str(),
 
849
                                svn_revnum_t(jrevision),
 
850
                                EnumMapper::toDepth(jdepth),
 
851
                                editor->delta_editor(),
 
852
                                editor->delta_baton(),
 
853
                                report_pool),);
 
854
  rp->set_reporter_data(raw_reporter, report_baton, editor.release());
 
855
}
 
856
 
 
857
// TODO: diff
 
858
 
 
859
void
 
860
RemoteSession::getLog(jobject jpaths,
 
861
                      jlong jstartrev, jlong jendrev, jint jlimit,
 
862
                      jboolean jstrict_node_history,
 
863
                      jboolean jdiscover_changed_paths,
 
864
                      jboolean jinclude_merged_revisions,
 
865
                      jobject jrevprops, jobject jlog_callback)
 
866
{
 
867
  Iterator pathiter(jpaths);
 
868
  if (JNIUtil::isJavaExceptionThrown())
 
869
    return;
 
870
  Iterator revpropiter(jrevprops);
 
871
  if (JNIUtil::isJavaExceptionThrown())
 
872
    return;
 
873
  LogMessageCallback receiver(jlog_callback);
 
874
 
 
875
  SVN::Pool subPool(pool);
 
876
  const apr_array_header_t* paths = build_string_array(pathiter,
 
877
                                                       true, subPool);
 
878
  if (JNIUtil::isJavaExceptionThrown())
 
879
    return;
 
880
  const apr_array_header_t* revprops = (jrevprops != NULL)
 
881
                                        ? build_string_array(revpropiter,
 
882
                                                             false, subPool)
 
883
                                        : NULL;
 
884
  if (JNIUtil::isJavaExceptionThrown())
 
885
    return;
 
886
 
 
887
  SVN_JNI_ERR(svn_ra_get_log2(m_session, paths,
 
888
                              svn_revnum_t(jstartrev), svn_revnum_t(jendrev),
 
889
                              int(jlimit),
 
890
                              bool(jdiscover_changed_paths),
 
891
                              bool(jstrict_node_history),
 
892
                              bool(jinclude_merged_revisions),
 
893
                              revprops,
 
894
                              receiver.callback, &receiver,
 
895
                              subPool.getPool()),);
 
896
}
 
897
 
 
898
jobject
 
899
RemoteSession::checkPath(jstring jpath, jlong jrevision)
 
900
{
 
901
  SVN::Pool subPool(pool);
 
902
  Relpath path(jpath, subPool);
 
903
  if (JNIUtil::isExceptionThrown())
 
904
    return NULL;
 
905
  SVN_JNI_ERR(path.error_occurred(), NULL);
 
906
 
 
907
  svn_node_kind_t kind;
 
908
  SVN_JNI_ERR(svn_ra_check_path(m_session, path.c_str(),
 
909
                                svn_revnum_t(jrevision),
 
910
                                &kind, subPool.getPool()),
 
911
              NULL);
 
912
 
 
913
  return EnumMapper::mapNodeKind(kind);
 
914
}
 
915
 
 
916
jobject
 
917
RemoteSession::stat(jstring jpath, jlong jrevision)
 
918
{
 
919
  SVN::Pool subPool(pool);
 
920
  Relpath path(jpath, subPool);
 
921
  if (JNIUtil::isExceptionThrown())
 
922
    return NULL;
 
923
  SVN_JNI_ERR(path.error_occurred(), NULL);
 
924
 
 
925
  svn_dirent_t* dirent;
 
926
  SVN_JNI_ERR(svn_ra_stat(m_session, path.c_str(),
 
927
                          svn_revnum_t(jrevision),
 
928
                          &dirent, subPool.getPool()),
 
929
              NULL);
 
930
 
 
931
  if (dirent)
 
932
    return CreateJ::DirEntry(path.c_str(), path.c_str(), dirent);
 
933
  return NULL;
 
934
}
 
935
 
 
936
namespace {
 
937
apr_array_header_t*
 
938
long_iterable_to_revnum_array(jobject jlong_iterable, apr_pool_t* pool)
 
939
{
 
940
 
 
941
  JNIEnv* env = JNIUtil::getEnv();
 
942
 
 
943
  jclass cls = env->FindClass("java/lang/Long");
 
944
  if (JNIUtil::isExceptionThrown())
 
945
    return NULL;
 
946
 
 
947
  static jmethodID mid = 0;
 
948
  if (0 == mid)
 
949
    {
 
950
      mid = env->GetMethodID(cls, "longValue", "()J");
 
951
      if (JNIUtil::isExceptionThrown())
 
952
        return NULL;
 
953
    }
 
954
 
 
955
  apr_array_header_t* array = apr_array_make(pool, 0, sizeof(svn_revnum_t));
 
956
  Iterator iter(jlong_iterable);
 
957
  while (iter.hasNext())
 
958
    {
 
959
      const jlong entry = env->CallLongMethod(iter.next(), mid);
 
960
      if (JNIUtil::isExceptionThrown())
 
961
        return NULL;
 
962
      APR_ARRAY_PUSH(array, svn_revnum_t) = svn_revnum_t(entry);
 
963
    }
 
964
  return array;
 
965
}
 
966
 
 
967
jobject
 
968
location_hash_to_map(apr_hash_t* locations, apr_pool_t* scratch_pool)
 
969
{
 
970
  JNIEnv* env = JNIUtil::getEnv();
 
971
 
 
972
  jclass long_cls = env->FindClass("java/lang/Long");
 
973
  if (JNIUtil::isExceptionThrown())
 
974
    return NULL;
 
975
 
 
976
  static jmethodID long_ctor = 0;
 
977
  if (0 == long_ctor)
 
978
    {
 
979
      long_ctor = env->GetMethodID(long_cls, "<init>", "(J)V");
 
980
      if (JNIUtil::isExceptionThrown())
 
981
        return NULL;
 
982
    }
 
983
 
 
984
  jclass hash_cls = env->FindClass("java/util/HashMap");
 
985
  if (JNIUtil::isExceptionThrown())
 
986
    return NULL;
 
987
 
 
988
  static jmethodID hash_ctor = 0;
 
989
  if (0 == hash_ctor)
 
990
    {
 
991
      hash_ctor = env->GetMethodID(hash_cls, "<init>", "()V");
 
992
      if (JNIUtil::isExceptionThrown())
 
993
        return NULL;
 
994
    }
 
995
 
 
996
  static jmethodID hash_put = 0;
 
997
  if (0 == hash_put)
 
998
    {
 
999
      hash_put = env->GetMethodID(hash_cls, "put",
 
1000
                                  "(Ljava/lang/Object;Ljava/lang/Object;"
 
1001
                                  ")Ljava/lang/Object;");
 
1002
      if (JNIUtil::isExceptionThrown())
 
1003
        return NULL;
 
1004
    }
 
1005
 
 
1006
  jobject result = env->NewObject(hash_cls, hash_ctor);
 
1007
  if (JNIUtil::isExceptionThrown())
 
1008
    return NULL;
 
1009
 
 
1010
  if (!locations)
 
1011
    return result;
 
1012
 
 
1013
  for (apr_hash_index_t* hi = apr_hash_first(scratch_pool, locations);
 
1014
       hi; hi = apr_hash_next(hi))
 
1015
    {
 
1016
      const void* key;
 
1017
      void* val;
 
1018
 
 
1019
      apr_hash_this(hi, &key, NULL, &val);
 
1020
 
 
1021
      jobject jkey = env->NewObject(
 
1022
          long_cls, long_ctor, jlong(*static_cast<const svn_revnum_t*>(key)));
 
1023
      if (JNIUtil::isExceptionThrown())
 
1024
        return NULL;
 
1025
      jstring jval = JNIUtil::makeJString(static_cast<const char*>(val));
 
1026
      if (JNIUtil::isExceptionThrown())
 
1027
        return NULL;
 
1028
 
 
1029
      env->CallObjectMethod(result, hash_put, jkey, jval);
 
1030
      if (JNIUtil::isExceptionThrown())
 
1031
        return NULL;
 
1032
 
 
1033
      env->DeleteLocalRef(jkey);
 
1034
      env->DeleteLocalRef(jval);
 
1035
    }
 
1036
 
 
1037
  return result;
 
1038
}
 
1039
} // anonymous namespace
 
1040
 
 
1041
jobject
 
1042
RemoteSession::getLocations(jstring jpath, jlong jpeg_revision,
 
1043
                            jobject jlocation_revisions)
 
1044
{
 
1045
  if (!jpath || !jlocation_revisions)
 
1046
    return NULL;
 
1047
 
 
1048
  SVN::Pool subPool(pool);
 
1049
  Relpath path(jpath, subPool);
 
1050
  if (JNIUtil::isExceptionThrown())
 
1051
    return NULL;
 
1052
  SVN_JNI_ERR(path.error_occurred(), NULL);
 
1053
 
 
1054
  apr_array_header_t* location_revisions =
 
1055
    long_iterable_to_revnum_array(jlocation_revisions, subPool.getPool());
 
1056
  if (!location_revisions)
 
1057
    return NULL;
 
1058
 
 
1059
  apr_hash_t* locations;
 
1060
  SVN_JNI_ERR(svn_ra_get_locations(m_session, &locations,
 
1061
                                   path.c_str(), svn_revnum_t(jpeg_revision),
 
1062
                                   location_revisions, subPool.getPool()),
 
1063
              NULL);
 
1064
  return location_hash_to_map(locations, subPool.getPool());
 
1065
}
 
1066
 
 
1067
namespace {
 
1068
class LocationSegmentHandler
 
1069
{
 
1070
public:
 
1071
  static svn_error_t* callback(svn_location_segment_t* segment,
 
1072
                               void* baton, apr_pool_t*)
 
1073
    {
 
1074
      LocationSegmentHandler* const self =
 
1075
        static_cast<LocationSegmentHandler*>(baton);
 
1076
      SVN_ERR_ASSERT(self->m_jcallback != NULL);
 
1077
      self->call(segment);
 
1078
      SVN_ERR(JNIUtil::checkJavaException(SVN_ERR_BASE));
 
1079
      return SVN_NO_ERROR;
 
1080
    }
 
1081
 
 
1082
  LocationSegmentHandler(jobject jcallback)
 
1083
    : m_jcallback(jcallback),
 
1084
      m_call_mid(0)
 
1085
    {
 
1086
      JNIEnv* env = JNIUtil::getEnv();
 
1087
      jclass cls = env->GetObjectClass(jcallback);
 
1088
      if (JNIUtil::isJavaExceptionThrown())
 
1089
        return;
 
1090
 
 
1091
      m_call_mid = env->GetMethodID(
 
1092
          cls, "doSegment", "(" JAVAHL_ARG("/ISVNRemote$LocationSegment;") ")V");
 
1093
      if (JNIUtil::isJavaExceptionThrown())
 
1094
        return;
 
1095
    }
 
1096
 
 
1097
private:
 
1098
  void call(svn_location_segment_t* segment)
 
1099
    {
 
1100
      JNIEnv* env = JNIUtil::getEnv();
 
1101
      jclass cls = env->FindClass(JAVAHL_CLASS("/ISVNRemote$LocationSegment"));
 
1102
      if (JNIUtil::isJavaExceptionThrown())
 
1103
        return;
 
1104
 
 
1105
      static jmethodID mid = 0;
 
1106
      if (mid == 0)
 
1107
        {
 
1108
          mid = env->GetMethodID(cls, "<init>",
 
1109
                                 "(Ljava/lang/String;JJ)V");
 
1110
          if (JNIUtil::isJavaExceptionThrown())
 
1111
            return;
 
1112
        }
 
1113
 
 
1114
      jstring jpath = JNIUtil::makeJString(segment->path);
 
1115
      if (JNIUtil::isJavaExceptionThrown())
 
1116
        return;
 
1117
 
 
1118
      env->CallVoidMethod(m_jcallback, m_call_mid,
 
1119
                          env->NewObject(cls, mid, jpath,
 
1120
                                         jlong(segment->range_start),
 
1121
                                         jlong(segment->range_end)));
 
1122
      if (JNIUtil::isJavaExceptionThrown())
 
1123
        return;
 
1124
      env->DeleteLocalRef(jpath);
 
1125
    }
 
1126
 
 
1127
  jobject m_jcallback;
 
1128
  jmethodID m_call_mid;
 
1129
};
 
1130
} // anonymous namespace
 
1131
 
 
1132
void
 
1133
RemoteSession::getLocationSegments(jstring jpath, jlong jpeg_revision,
 
1134
                                   jlong jstart_revision, jlong jend_revision,
 
1135
                                   jobject jcallback)
 
1136
{
 
1137
  SVN::Pool subPool(pool);
 
1138
  Relpath path(jpath, subPool);
 
1139
  if (JNIUtil::isExceptionThrown())
 
1140
    return;
 
1141
  SVN_JNI_ERR(path.error_occurred(), );
 
1142
 
 
1143
  LocationSegmentHandler handler(jcallback);
 
1144
  if (JNIUtil::isExceptionThrown())
 
1145
    return ;
 
1146
 
 
1147
  SVN_JNI_ERR(svn_ra_get_location_segments(m_session, path.c_str(),
 
1148
                                           svn_revnum_t(jpeg_revision),
 
1149
                                           svn_revnum_t(jstart_revision),
 
1150
                                           svn_revnum_t(jend_revision),
 
1151
                                           handler.callback, &handler,
 
1152
                                           subPool.getPool()),);
 
1153
}
 
1154
 
 
1155
namespace {
 
1156
class FileRevisionHandler
 
1157
{
 
1158
public:
 
1159
  static svn_error_t* callback(void* baton,
 
1160
                               const char* path, svn_revnum_t revision,
 
1161
                               apr_hash_t* revision_props,
 
1162
                               // We ignore the deltas as they're not
 
1163
                               // exposed in the JavaHL API.
 
1164
                               svn_boolean_t result_of_merge,
 
1165
                               svn_txdelta_window_handler_t* delta_handler,
 
1166
                               void** delta_handler_baton,
 
1167
                               apr_array_header_t* prop_diffs,
 
1168
                               apr_pool_t* scratch_pool)
 
1169
    {
 
1170
      if (delta_handler)
 
1171
        *delta_handler = svn_delta_noop_window_handler;
 
1172
      if (delta_handler_baton)
 
1173
        *delta_handler_baton = NULL;
 
1174
 
 
1175
      FileRevisionHandler* const self =
 
1176
        static_cast<FileRevisionHandler*>(baton);
 
1177
      SVN_ERR_ASSERT(self->m_jcallback != NULL);
 
1178
      self->call(path, revision, revision_props,
 
1179
                result_of_merge, prop_diffs,
 
1180
                (delta_handler != NULL),
 
1181
                scratch_pool);
 
1182
      SVN_ERR(JNIUtil::checkJavaException(SVN_ERR_BASE));
 
1183
      return SVN_NO_ERROR;
 
1184
    }
 
1185
 
 
1186
  FileRevisionHandler(jobject jcallback)
 
1187
    : m_jcallback(jcallback),
 
1188
      m_call_mid(0)
 
1189
    {
 
1190
      JNIEnv* env = JNIUtil::getEnv();
 
1191
      jclass cls = env->GetObjectClass(jcallback);
 
1192
      if (JNIUtil::isJavaExceptionThrown())
 
1193
        return;
 
1194
 
 
1195
      m_call_mid = env->GetMethodID(
 
1196
          cls, "doRevision", "(" JAVAHL_ARG("/ISVNRemote$FileRevision;") ")V");
 
1197
      if (JNIUtil::isJavaExceptionThrown())
 
1198
        return;
 
1199
    }
 
1200
 
 
1201
private:
 
1202
  void call(const char* path, svn_revnum_t revision,
 
1203
           apr_hash_t* revision_props,
 
1204
           svn_boolean_t result_of_merge,
 
1205
           apr_array_header_t* prop_diffs,
 
1206
           svn_boolean_t has_text_delta,
 
1207
           apr_pool_t* scratch_pool)
 
1208
    {
 
1209
      JNIEnv* env = JNIUtil::getEnv();
 
1210
      jclass cls = env->FindClass(JAVAHL_CLASS("/ISVNRemote$FileRevision"));
 
1211
      if (JNIUtil::isJavaExceptionThrown())
 
1212
        return;
 
1213
 
 
1214
      static jmethodID mid = 0;
 
1215
      if (mid == 0)
 
1216
        {
 
1217
          mid = env->GetMethodID(cls, "<init>",
 
1218
                                 "(Ljava/lang/String;JZ"
 
1219
                                 "Ljava/util/Map;Ljava/util/Map;Z)V");
 
1220
          if (JNIUtil::isJavaExceptionThrown())
 
1221
            return;
 
1222
        }
 
1223
 
 
1224
      jstring jpath = JNIUtil::makeJString(path);
 
1225
      if (JNIUtil::isJavaExceptionThrown())
 
1226
        return;
 
1227
      jobject jrevprops = CreateJ::PropertyMap(revision_props, scratch_pool);
 
1228
      if (JNIUtil::isJavaExceptionThrown())
 
1229
        return;
 
1230
      jobject jpropdelta = CreateJ::PropertyMap(prop_diffs, scratch_pool);
 
1231
      if (JNIUtil::isJavaExceptionThrown())
 
1232
        return;
 
1233
 
 
1234
      env->CallVoidMethod(m_jcallback, m_call_mid,
 
1235
                          env->NewObject(cls, mid, jpath, jlong(revision),
 
1236
                                         jboolean(result_of_merge),
 
1237
                                         jrevprops, jpropdelta,
 
1238
                                         jboolean(has_text_delta)));
 
1239
      if (JNIUtil::isJavaExceptionThrown())
 
1240
        return;
 
1241
      env->DeleteLocalRef(jpath);
 
1242
      env->DeleteLocalRef(jrevprops);
 
1243
      env->DeleteLocalRef(jpropdelta);
 
1244
    }
 
1245
 
 
1246
  jobject m_jcallback;
 
1247
  jmethodID m_call_mid;
 
1248
};
 
1249
} // anonymous namespace
 
1250
 
 
1251
void
 
1252
RemoteSession::getFileRevisions(jstring jpath,
 
1253
                                jlong jstart_revision, jlong jend_revision,
 
1254
                                jboolean jinclude_merged_revisions,
 
1255
                                jobject jcallback)
 
1256
{
 
1257
  SVN::Pool subPool(pool);
 
1258
  Relpath path(jpath, subPool);
 
1259
  if (JNIUtil::isExceptionThrown())
 
1260
    return;
 
1261
  SVN_JNI_ERR(path.error_occurred(), );
 
1262
 
 
1263
  FileRevisionHandler handler(jcallback);
 
1264
  if (JNIUtil::isExceptionThrown())
 
1265
    return;
 
1266
 
 
1267
  SVN_JNI_ERR(svn_ra_get_file_revs2(m_session, path.c_str(),
 
1268
                                    svn_revnum_t(jstart_revision),
 
1269
                                    svn_revnum_t(jend_revision),
 
1270
                                    bool(jinclude_merged_revisions),
 
1271
                                    handler.callback, &handler,
 
1272
                                    subPool.getPool()),);
 
1273
}
 
1274
 
 
1275
// TODO: lock
 
1276
// TODO: unlock
 
1277
// TODO: getLock
 
1278
 
 
1279
jobject
 
1280
RemoteSession::getLocks(jstring jpath, jobject jdepth)
 
1281
{
 
1282
  svn_depth_t depth = EnumMapper::toDepth(jdepth);
 
1283
  if (JNIUtil::isExceptionThrown())
 
1284
    return NULL;
 
1285
 
 
1286
  SVN::Pool subPool(pool);
 
1287
  Relpath path(jpath, subPool);
 
1288
  if (JNIUtil::isExceptionThrown())
 
1289
    return NULL;
 
1290
  SVN_JNI_ERR(path.error_occurred(), NULL);
 
1291
 
 
1292
  apr_hash_t *locks;
 
1293
  SVN_JNI_ERR(svn_ra_get_locks2(m_session, &locks, path.c_str(), depth,
 
1294
                                subPool.getPool()),
 
1295
              NULL);
 
1296
 
 
1297
  return CreateJ::LockMap(locks, subPool.getPool());
 
1298
}
 
1299
 
 
1300
// TODO: replayRange
 
1301
// TODO: replay
 
1302
// TODO: getDeletedRevision
 
1303
// TODO: getInheritedProperties
 
1304
 
 
1305
jboolean
 
1306
RemoteSession::hasCapability(jstring jcapability)
 
1307
{
 
1308
  JNIStringHolder capability(jcapability);
 
1309
  if (JNIUtil::isExceptionThrown())
 
1310
    return false;
 
1311
 
 
1312
  SVN::Pool subPool(pool);
 
1313
  svn_boolean_t has;
 
1314
  SVN_JNI_ERR(svn_ra_has_capability(m_session, &has, capability,
 
1315
                                    subPool.getPool()),
 
1316
              false);
 
1317
 
 
1318
  return jboolean(has);
 
1319
}