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

« back to all changes in this revision

Viewing changes to subversion/libsvn_ra/ra_loader.c

  • 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:
35
35
 
36
36
#include "svn_hash.h"
37
37
#include "svn_version.h"
 
38
#include "svn_time.h"
38
39
#include "svn_types.h"
39
40
#include "svn_error.h"
40
41
#include "svn_error_codes.h"
51
52
#include "ra_loader.h"
52
53
#include "deprecated.h"
53
54
 
 
55
#include "private/svn_auth_private.h"
54
56
#include "private/svn_ra_private.h"
55
57
#include "svn_private_config.h"
56
58
 
230
232
 
231
233
svn_error_t *svn_ra_initialize(apr_pool_t *pool)
232
234
{
 
235
#if defined(SVN_USE_DSO) && APR_HAS_DSO
 
236
  /* Ensure that DSO subsystem is initialized early as possible if
 
237
     we're going to use it. */
 
238
  SVN_ERR(svn_dso_initialize2());
 
239
#endif
233
240
  return SVN_NO_ERROR;
234
241
}
235
242
 
259
266
                          apr_pool_t *pool)
260
267
{
261
268
  apr_pool_t *sesspool = svn_pool_create(pool);
 
269
  apr_pool_t *scratch_pool = svn_pool_create(sesspool);
262
270
  svn_ra_session_t *session;
263
271
  const struct ra_lib_defn *defn;
264
272
  const svn_ra__vtable_t *vtable = NULL;
265
 
  svn_config_t *servers = NULL;
266
 
  const char *server_group;
267
273
  apr_uri_t repos_URI;
268
274
  apr_status_t apr_err;
 
275
  svn_error_t *err;
269
276
#ifdef CHOOSABLE_DAV_MODULE
270
277
  const char *http_library = DEFAULT_HTTP_LIBRARY;
271
278
#endif
272
 
  /* Auth caching parameters. */
273
 
  svn_boolean_t store_passwords = SVN_CONFIG_DEFAULT_OPTION_STORE_PASSWORDS;
274
 
  svn_boolean_t store_auth_creds = SVN_CONFIG_DEFAULT_OPTION_STORE_AUTH_CREDS;
275
 
  const char *store_plaintext_passwords
276
 
    = SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS;
277
 
  svn_boolean_t store_pp = SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP;
278
 
  const char *store_pp_plaintext
279
 
    = SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT;
280
 
  const char *corrected_url;
 
279
  svn_auth_baton_t *auth_baton;
281
280
 
282
281
  /* Initialize the return variable. */
283
282
  *session_p = NULL;
293
292
                             repos_URL);
294
293
 
295
294
  if (callbacks->auth_baton)
296
 
    {
297
 
      /* The 'store-passwords' and 'store-auth-creds' parameters used to
298
 
       * live in SVN_CONFIG_CATEGORY_CONFIG. For backward compatibility,
299
 
       * if values for these parameters have already been set by our
300
 
       * callers, we use those values as defaults.
301
 
       *
302
 
       * Note that we can only catch the case where users explicitly set
303
 
       * "store-passwords = no" or 'store-auth-creds = no".
304
 
       *
305
 
       * However, since the default value for both these options is
306
 
       * currently (and has always been) "yes", users won't know
307
 
       * the difference if they set "store-passwords = yes" or
308
 
       * "store-auth-creds = yes" -- they'll get the expected behaviour.
309
 
       */
310
 
 
311
 
      if (svn_auth_get_parameter(callbacks->auth_baton,
312
 
                                 SVN_AUTH_PARAM_DONT_STORE_PASSWORDS) != NULL)
313
 
        store_passwords = FALSE;
314
 
 
315
 
      if (svn_auth_get_parameter(callbacks->auth_baton,
316
 
                                 SVN_AUTH_PARAM_NO_AUTH_CACHE) != NULL)
317
 
        store_auth_creds = FALSE;
318
 
    }
319
 
 
 
295
    SVN_ERR(svn_auth__make_session_auth(&auth_baton,
 
296
                                        callbacks->auth_baton, config,
 
297
                                        repos_URI.hostname,
 
298
                                        sesspool, scratch_pool));
 
299
  else
 
300
    auth_baton = NULL;
 
301
 
 
302
#ifdef CHOOSABLE_DAV_MODULE
320
303
  if (config)
321
304
    {
 
305
      svn_config_t *servers = NULL;
 
306
      const char *server_group = NULL;
 
307
 
322
308
      /* Grab the 'servers' config. */
323
309
      servers = svn_hash_gets(config, SVN_CONFIG_CATEGORY_SERVERS);
324
310
      if (servers)
325
311
        {
326
312
          /* First, look in the global section. */
327
313
 
328
 
          SVN_ERR(svn_config_get_bool
329
 
            (servers, &store_passwords, SVN_CONFIG_SECTION_GLOBAL,
330
 
             SVN_CONFIG_OPTION_STORE_PASSWORDS,
331
 
             store_passwords));
332
 
 
333
 
          SVN_ERR(svn_config_get_yes_no_ask
334
 
            (servers, &store_plaintext_passwords, SVN_CONFIG_SECTION_GLOBAL,
335
 
             SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS,
336
 
             SVN_CONFIG_DEFAULT_OPTION_STORE_PLAINTEXT_PASSWORDS));
337
 
 
338
 
          SVN_ERR(svn_config_get_bool
339
 
            (servers, &store_pp, SVN_CONFIG_SECTION_GLOBAL,
340
 
             SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP,
341
 
             store_pp));
342
 
 
343
 
          SVN_ERR(svn_config_get_yes_no_ask
344
 
            (servers, &store_pp_plaintext,
345
 
             SVN_CONFIG_SECTION_GLOBAL,
346
 
             SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
347
 
             SVN_CONFIG_DEFAULT_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT));
348
 
 
349
 
          SVN_ERR(svn_config_get_bool
350
 
            (servers, &store_auth_creds, SVN_CONFIG_SECTION_GLOBAL,
351
 
              SVN_CONFIG_OPTION_STORE_AUTH_CREDS,
352
 
              store_auth_creds));
353
 
 
354
314
          /* Find out where we're about to connect to, and
355
315
           * try to pick a server group based on the destination. */
356
316
          server_group = svn_config_find_group(servers, repos_URI.hostname,
357
317
                                               SVN_CONFIG_SECTION_GROUPS,
358
318
                                               sesspool);
359
319
 
360
 
          if (server_group)
361
 
            {
362
 
              /* Override global auth caching parameters with the ones
363
 
               * for the server group, if any. */
364
 
              SVN_ERR(svn_config_get_bool(servers, &store_auth_creds,
365
 
                                          server_group,
366
 
                                          SVN_CONFIG_OPTION_STORE_AUTH_CREDS,
367
 
                                          store_auth_creds));
368
 
 
369
 
              SVN_ERR(svn_config_get_bool(servers, &store_passwords,
370
 
                                          server_group,
371
 
                                          SVN_CONFIG_OPTION_STORE_PASSWORDS,
372
 
                                          store_passwords));
373
 
 
374
 
              SVN_ERR(svn_config_get_yes_no_ask
375
 
                (servers, &store_plaintext_passwords, server_group,
376
 
                 SVN_CONFIG_OPTION_STORE_PLAINTEXT_PASSWORDS,
377
 
                 store_plaintext_passwords));
378
 
 
379
 
              SVN_ERR(svn_config_get_bool
380
 
                (servers, &store_pp,
381
 
                 server_group, SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP,
382
 
                 store_pp));
383
 
 
384
 
              SVN_ERR(svn_config_get_yes_no_ask
385
 
                (servers, &store_pp_plaintext, server_group,
386
 
                 SVN_CONFIG_OPTION_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
387
 
                 store_pp_plaintext));
388
 
            }
389
 
#ifdef CHOOSABLE_DAV_MODULE
390
320
          /* Now, which DAV-based RA method do we want to use today? */
391
321
          http_library
392
322
            = svn_config_get_server_setting(servers,
399
329
                                     _("Invalid config: unknown HTTP library "
400
330
                                       "'%s'"),
401
331
                                     http_library);
 
332
        }
 
333
    }
402
334
#endif
403
 
        }
404
 
    }
405
 
 
406
 
  if (callbacks->auth_baton)
407
 
    {
408
 
      /* Save auth caching parameters in the auth parameter hash. */
409
 
      if (! store_passwords)
410
 
        svn_auth_set_parameter(callbacks->auth_baton,
411
 
                               SVN_AUTH_PARAM_DONT_STORE_PASSWORDS, "");
412
 
 
413
 
      svn_auth_set_parameter(callbacks->auth_baton,
414
 
                             SVN_AUTH_PARAM_STORE_PLAINTEXT_PASSWORDS,
415
 
                             store_plaintext_passwords);
416
 
 
417
 
      if (! store_pp)
418
 
        svn_auth_set_parameter(callbacks->auth_baton,
419
 
                               SVN_AUTH_PARAM_DONT_STORE_SSL_CLIENT_CERT_PP,
420
 
                               "");
421
 
 
422
 
      svn_auth_set_parameter(callbacks->auth_baton,
423
 
                             SVN_AUTH_PARAM_STORE_SSL_CLIENT_CERT_PP_PLAINTEXT,
424
 
                             store_pp_plaintext);
425
 
 
426
 
      if (! store_auth_creds)
427
 
        svn_auth_set_parameter(callbacks->auth_baton,
428
 
                               SVN_AUTH_PARAM_NO_AUTH_CACHE, "");
429
 
    }
430
335
 
431
336
  /* Find the library. */
432
337
  for (defn = ra_libraries; defn->ra_name != NULL; ++defn)
445
350
 
446
351
          if (! initfunc)
447
352
            SVN_ERR(load_ra_module(&initfunc, NULL, defn->ra_name,
448
 
                                   sesspool));
 
353
                                   scratch_pool));
449
354
          if (! initfunc)
450
355
            /* Library not found. */
451
356
            continue;
452
357
 
453
 
          SVN_ERR(initfunc(svn_ra_version(), &vtable, sesspool));
 
358
          SVN_ERR(initfunc(svn_ra_version(), &vtable, scratch_pool));
454
359
 
455
360
          SVN_ERR(check_ra_version(vtable->get_version(), scheme));
456
361
 
457
 
          if (! has_scheme_of(vtable->get_schemes(sesspool), repos_URL))
 
362
          if (! has_scheme_of(vtable->get_schemes(scratch_pool), repos_URL))
458
363
            /* Library doesn't support the scheme at runtime. */
459
364
            continue;
460
365
 
476
381
  session->pool = sesspool;
477
382
 
478
383
  /* Ask the library to open the session. */
479
 
  SVN_ERR_W(vtable->open_session(session, &corrected_url, repos_URL,
480
 
                                 callbacks, callback_baton, config, sesspool),
481
 
            apr_psprintf(pool, "Unable to connect to a repository at URL '%s'",
482
 
                         repos_URL));
 
384
  err = vtable->open_session(session, corrected_url_p,
 
385
                             repos_URL,
 
386
                             callbacks, callback_baton, auth_baton,
 
387
                             config, sesspool, scratch_pool);
 
388
 
 
389
  if (err)
 
390
    {
 
391
      svn_pool_destroy(sesspool); /* Includes scratch_pool */
 
392
      if (err->apr_err == SVN_ERR_RA_SESSION_URL_MISMATCH)
 
393
        return svn_error_trace(err);
 
394
 
 
395
      return svn_error_createf(
 
396
                SVN_ERR_RA_CANNOT_CREATE_SESSION, err,
 
397
                _("Unable to connect to a repository at URL '%s'"),
 
398
                repos_URL);
 
399
    }
483
400
 
484
401
  /* If the session open stuff detected a server-provided URL
485
402
     correction (a 301 or 302 redirect response during the initial
486
403
     OPTIONS request), then kill the session so the caller can decide
487
404
     what to do. */
488
 
  if (corrected_url_p && corrected_url)
 
405
  if (corrected_url_p && *corrected_url_p)
489
406
    {
490
 
      if (! svn_path_is_url(corrected_url))
491
 
        {
492
 
          /* RFC1945 and RFC2616 state that the Location header's
493
 
             value (from whence this CORRECTED_URL ultimately comes),
494
 
             if present, must be an absolute URI.  But some Apache
495
 
             versions (those older than 2.2.11, it seems) transmit
496
 
             only the path portion of the URI.  See issue #3775 for
497
 
             details. */
498
 
          apr_uri_t corrected_URI = repos_URI;
499
 
          corrected_URI.path = (char *)corrected_url;
500
 
          corrected_url = apr_uri_unparse(pool, &corrected_URI, 0);
501
 
        }
502
 
      *corrected_url_p = svn_uri_canonicalize(corrected_url, pool);
503
 
      svn_pool_destroy(sesspool);
 
407
      /* *session_p = NULL; */
 
408
      *corrected_url_p = apr_pstrdup(pool, *corrected_url_p);
 
409
      svn_pool_destroy(sesspool); /* Includes scratch_pool */
504
410
      return SVN_NO_ERROR;
505
411
    }
506
412
 
514
420
        {
515
421
          /* Duplicate the uuid as it is allocated in sesspool */
516
422
          repository_uuid = apr_pstrdup(pool, repository_uuid);
517
 
          svn_pool_destroy(sesspool);
 
423
          svn_pool_destroy(sesspool); /* includes scratch_pool */
518
424
          return svn_error_createf(SVN_ERR_RA_UUID_MISMATCH, NULL,
519
425
                                   _("Repository UUID '%s' doesn't match "
520
426
                                     "expected UUID '%s'"),
522
428
        }
523
429
    }
524
430
 
 
431
  svn_pool_destroy(scratch_pool);
525
432
  *session_p = session;
526
433
  return SVN_NO_ERROR;
527
434
}
528
435
 
 
436
svn_error_t *
 
437
svn_ra__dup_session(svn_ra_session_t **new_session,
 
438
                    svn_ra_session_t *old_session,
 
439
                    const char *session_url,
 
440
                    apr_pool_t *result_pool,
 
441
                    apr_pool_t *scratch_pool)
 
442
{
 
443
  svn_ra_session_t *session;
 
444
 
 
445
  if (session_url)
 
446
    {
 
447
      const char *dummy;
 
448
 
 
449
      /* This verifies in new_session_url is in the repository */
 
450
      SVN_ERR(svn_ra_get_path_relative_to_root(old_session,
 
451
                                               &dummy,
 
452
                                               session_url,
 
453
                                               scratch_pool));
 
454
    }
 
455
  else
 
456
    SVN_ERR(svn_ra_get_session_url(old_session, &session_url, scratch_pool));
 
457
 
 
458
  /* Create the session object. */
 
459
  session = apr_pcalloc(result_pool, sizeof(*session));
 
460
  session->cancel_func = old_session->cancel_func;
 
461
  session->cancel_baton = old_session->cancel_baton;
 
462
  session->vtable = old_session->vtable;
 
463
  session->pool = result_pool;
 
464
 
 
465
  SVN_ERR(old_session->vtable->dup_session(session,
 
466
                                           old_session,
 
467
                                           session_url,
 
468
                                           result_pool,
 
469
                                           scratch_pool));
 
470
 
 
471
  *new_session = session;
 
472
  return SVN_NO_ERROR;
 
473
}
 
474
 
529
475
svn_error_t *svn_ra_reparent(svn_ra_session_t *session,
530
476
                             const char *url,
531
477
                             apr_pool_t *pool)
650
596
  return session->vtable->rev_prop(session, rev, name, value, pool);
651
597
}
652
598
 
653
 
struct ccw_baton
654
 
{
655
 
  svn_commit_callback2_t original_callback;
656
 
  void *original_baton;
657
 
 
658
 
  svn_ra_session_t *session;
659
 
};
660
 
 
661
 
/* Wrapper which populates the repos_root field of the commit_info struct */
662
 
static svn_error_t *
663
 
commit_callback_wrapper(const svn_commit_info_t *commit_info,
664
 
                        void *baton,
665
 
                        apr_pool_t *pool)
666
 
{
667
 
  struct ccw_baton *ccwb = baton;
668
 
  svn_commit_info_t *ci = svn_commit_info_dup(commit_info, pool);
669
 
 
670
 
  SVN_ERR(svn_ra_get_repos_root2(ccwb->session, &ci->repos_root, pool));
671
 
 
672
 
  return ccwb->original_callback(ci, ccwb->original_baton, pool);
673
 
}
674
 
 
675
 
 
676
 
/* Some RA layers do not correctly fill in REPOS_ROOT in commit_info, or
677
 
   they are third-party layers conforming to an older commit_info structure.
678
 
   Interpose a utility function to ensure the field is valid.  */
679
 
static void
680
 
remap_commit_callback(svn_commit_callback2_t *callback,
681
 
                      void **callback_baton,
682
 
                      svn_ra_session_t *session,
683
 
                      svn_commit_callback2_t original_callback,
684
 
                      void *original_baton,
685
 
                      apr_pool_t *result_pool)
686
 
{
687
 
  if (original_callback == NULL)
688
 
    {
689
 
      *callback = NULL;
690
 
      *callback_baton = NULL;
691
 
    }
692
 
  else
693
 
    {
694
 
      /* Allocate this in RESULT_POOL, since the callback will be called
695
 
         long after this function has returned. */
696
 
      struct ccw_baton *ccwb = apr_palloc(result_pool, sizeof(*ccwb));
697
 
 
698
 
      ccwb->session = session;
699
 
      ccwb->original_callback = original_callback;
700
 
      ccwb->original_baton = original_baton;
701
 
 
702
 
      *callback = commit_callback_wrapper;
703
 
      *callback_baton = ccwb;
704
 
    }
705
 
}
706
 
 
707
 
 
708
599
svn_error_t *svn_ra_get_commit_editor3(svn_ra_session_t *session,
709
600
                                       const svn_delta_editor_t **editor,
710
601
                                       void **edit_baton,
715
606
                                       svn_boolean_t keep_locks,
716
607
                                       apr_pool_t *pool)
717
608
{
718
 
  remap_commit_callback(&commit_callback, &commit_baton,
719
 
                        session, commit_callback, commit_baton,
720
 
                        pool);
721
 
 
722
609
  return session->vtable->get_commit_editor(session, editor, edit_baton,
723
610
                                            revprop_table,
724
611
                                            commit_callback, commit_baton,
925
812
                         svn_dirent_t **dirent,
926
813
                         apr_pool_t *pool)
927
814
{
 
815
  svn_error_t *err;
928
816
  SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
929
 
  return session->vtable->stat(session, path, revision, dirent, pool);
 
817
  err = session->vtable->stat(session, path, revision, dirent, pool);
 
818
 
 
819
  /* svnserve before 1.2 doesn't support the above, so fall back on
 
820
     a far less efficient, but still correct method. */
 
821
  if (err && err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)
 
822
    {
 
823
      /* ### TODO: Find out if we can somehow move this code in libsvn_ra_svn.
 
824
       */
 
825
      apr_pool_t *scratch_pool = svn_pool_create(pool);
 
826
      svn_node_kind_t kind;
 
827
 
 
828
      svn_error_clear(err);
 
829
 
 
830
      SVN_ERR(svn_ra_check_path(session, path, revision, &kind, scratch_pool));
 
831
 
 
832
      if (kind != svn_node_none)
 
833
        {
 
834
          const char *repos_root_url;
 
835
          const char *session_url;
 
836
 
 
837
          SVN_ERR(svn_ra_get_repos_root2(session, &repos_root_url,
 
838
                                         scratch_pool));
 
839
          SVN_ERR(svn_ra_get_session_url(session, &session_url,
 
840
                                         scratch_pool));
 
841
 
 
842
          if (!svn_path_is_empty(path))
 
843
            session_url = svn_path_url_add_component2(session_url, path,
 
844
                                                      scratch_pool);
 
845
 
 
846
          if (strcmp(session_url, repos_root_url) != 0)
 
847
            {
 
848
              svn_ra_session_t *parent_session;
 
849
              apr_hash_t *parent_ents;
 
850
              const char *parent_url, *base_name;
 
851
 
 
852
              /* Open another session to the path's parent.  This server
 
853
                 doesn't support svn_ra_reparent anyway, so don't try it. */
 
854
              svn_uri_split(&parent_url, &base_name, session_url,
 
855
                            scratch_pool);
 
856
 
 
857
              SVN_ERR(svn_ra__dup_session(&parent_session, session, parent_url,
 
858
                                          scratch_pool, scratch_pool));
 
859
 
 
860
              /* Get all parent's entries, no props. */
 
861
              SVN_ERR(svn_ra_get_dir2(parent_session, &parent_ents, NULL,
 
862
                                      NULL, "", revision, SVN_DIRENT_ALL,
 
863
                                      scratch_pool));
 
864
 
 
865
              /* Get the relevant entry. */
 
866
              *dirent = svn_hash_gets(parent_ents, base_name);
 
867
 
 
868
              if (*dirent)
 
869
                *dirent = svn_dirent_dup(*dirent, pool);
 
870
            }
 
871
          else
 
872
            {
 
873
              apr_hash_t *props;
 
874
              const svn_string_t *val;
 
875
 
 
876
              /* We can't get the directory entry for the repository root,
 
877
                 but we can still get the information we want.
 
878
                 The created-rev of the repository root must, by definition,
 
879
                 be rev. */
 
880
              *dirent = apr_pcalloc(pool, sizeof(**dirent));
 
881
              (*dirent)->kind = kind;
 
882
              (*dirent)->size = SVN_INVALID_FILESIZE;
 
883
 
 
884
              SVN_ERR(svn_ra_get_dir2(session, NULL, NULL, &props,
 
885
                                      "", revision, 0 /* no dirent fields */,
 
886
                                      scratch_pool));
 
887
              (*dirent)->has_props = (apr_hash_count(props) != 0);
 
888
 
 
889
              (*dirent)->created_rev = revision;
 
890
 
 
891
              SVN_ERR(svn_ra_rev_proplist(session, revision, &props,
 
892
                                          scratch_pool));
 
893
 
 
894
              val = svn_hash_gets(props, SVN_PROP_REVISION_DATE);
 
895
              if (val)
 
896
                SVN_ERR(svn_time_from_cstring(&(*dirent)->time, val->data,
 
897
                                              scratch_pool));
 
898
 
 
899
              val = svn_hash_gets(props, SVN_PROP_REVISION_AUTHOR);
 
900
              (*dirent)->last_author = val ? apr_pstrdup(pool, val->data)
 
901
                                           : NULL;
 
902
            }
 
903
        }
 
904
      else
 
905
        *dirent = NULL;
 
906
 
 
907
      svn_pool_clear(scratch_pool);
 
908
    }
 
909
  else
 
910
    SVN_ERR(err);
 
911
 
 
912
  return SVN_NO_ERROR;
930
913
}
931
914
 
932
915
svn_error_t *svn_ra_get_uuid2(svn_ra_session_t *session,
1030
1013
  if (include_merged_revisions)
1031
1014
    SVN_ERR(svn_ra__assert_mergeinfo_capable_server(session, NULL, pool));
1032
1015
 
1033
 
  if (start > end)
 
1016
  if (start > end || !SVN_IS_VALID_REVNUM(start))
1034
1017
    SVN_ERR(
1035
1018
     svn_ra__assert_capable_server(session,
1036
1019
                                   SVN_RA_CAPABILITY_GET_FILE_REVS_REVERSE,
1040
1023
  err = session->vtable->get_file_revs(session, path, start, end,
1041
1024
                                       include_merged_revisions,
1042
1025
                                       handler, handler_baton, pool);
1043
 
  if (err && (err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED))
 
1026
  if (err && (err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)
 
1027
      && !include_merged_revisions)
1044
1028
    {
1045
1029
      svn_error_clear(err);
1046
1030
 
1048
1032
      err = svn_ra__file_revs_from_log(session, path, start, end,
1049
1033
                                       handler, handler_baton, pool);
1050
1034
    }
1051
 
  return err;
 
1035
  return svn_error_trace(err);
1052
1036
}
1053
1037
 
1054
1038
svn_error_t *svn_ra_lock(svn_ra_session_t *session,
1063
1047
 
1064
1048
  for (hi = apr_hash_first(pool, path_revs); hi; hi = apr_hash_next(hi))
1065
1049
    {
1066
 
      const char *path = svn__apr_hash_index_key(hi);
 
1050
      const char *path = apr_hash_this_key(hi);
1067
1051
 
1068
1052
      SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
1069
1053
    }
1088
1072
 
1089
1073
  for (hi = apr_hash_first(pool, path_tokens); hi; hi = apr_hash_next(hi))
1090
1074
    {
1091
 
      const char *path = svn__apr_hash_index_key(hi);
 
1075
      const char *path = apr_hash_this_key(hi);
1092
1076
 
1093
1077
      SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
1094
1078
    }
1320
1304
                           apr_pool_t *result_pool,
1321
1305
                           apr_pool_t *scratch_pool)
1322
1306
{
1323
 
  svn_boolean_t iprop_capable;
1324
 
 
 
1307
  svn_error_t *err;
1325
1308
  /* Path must be relative. */
1326
1309
  SVN_ERR_ASSERT(svn_relpath_is_canonical(path));
1327
1310
 
1328
 
  SVN_ERR(svn_ra_has_capability(session, &iprop_capable,
1329
 
                                SVN_RA_CAPABILITY_INHERITED_PROPS,
1330
 
                                scratch_pool));
1331
 
 
1332
 
  if (iprop_capable)
1333
 
    {
1334
 
      SVN_ERR(session->vtable->get_inherited_props(session, iprops, path,
1335
 
                                                   revision, result_pool,
1336
 
                                                   scratch_pool));
1337
 
    }
1338
 
  else
1339
 
    {
 
1311
  err = session->vtable->get_inherited_props(session, iprops, path,
 
1312
                                             revision, result_pool,
 
1313
                                             scratch_pool);
 
1314
 
 
1315
  if (err && err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)
 
1316
    {
 
1317
      svn_error_clear(err);
 
1318
 
1340
1319
      /* Fallback for legacy servers. */
1341
1320
      SVN_ERR(svn_ra__get_inherited_props_walk(session, path, revision, iprops,
1342
1321
                                               result_pool, scratch_pool));
1343
1322
    }
 
1323
  else
 
1324
    SVN_ERR(err);
1344
1325
 
1345
1326
  return SVN_NO_ERROR;
1346
1327
}
1365
1346
      /* The specific RA layer does not have an implementation. Use our
1366
1347
         default shim over the normal commit editor.  */
1367
1348
 
1368
 
      /* Remap for RA layers exposing Ev1.  */
1369
 
      remap_commit_callback(&commit_callback, &commit_baton,
1370
 
                            session, commit_callback, commit_baton,
1371
 
                            result_pool);
1372
 
 
1373
1349
      return svn_error_trace(svn_ra__use_commit_shim(
1374
1350
                               editor,
1375
1351
                               session,