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

« back to all changes in this revision

Viewing changes to subversion/mod_dav_svn/repos.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:
56
56
#include "private/svn_log.h"
57
57
#include "private/svn_fspath.h"
58
58
#include "private/svn_repos_private.h"
 
59
#include "private/svn_sorts_private.h"
59
60
 
60
61
#include "dav_svn.h"
61
62
 
899
900
  comb->res.uri = dav_svn__build_uri(comb->priv.repos,
900
901
                                     DAV_SVN__BUILD_URI_BASELINE,
901
902
                                     comb->priv.root.rev, NULL,
902
 
                                     0 /* add_href */,
 
903
                                     FALSE /* add_href */,
903
904
                                     pool);
904
905
 
905
906
  return NULL;
1034
1035
  comb->res.exists = (kind != svn_node_none);
1035
1036
  comb->res.collection = (kind == svn_node_dir);
1036
1037
 
 
1038
  if (comb->res.exists
 
1039
      && comb->priv.r->method_number == M_MKCOL
 
1040
      && comb->priv.repos->is_svn_client)
 
1041
    {
 
1042
      /* mod_dav will now continue returning a generic HTTP_METHOD_NOT_ALLOWED
 
1043
         error, which doesn't produce nice output on SVN, nor gives any details
 
1044
         on why the operation failed.
 
1045
 
 
1046
         Let's error out a bit earlier and produce an error message that is
 
1047
         easier to understand for both clients and users. */
 
1048
 
 
1049
      /* It would be nice if we could error out a bit later (see issue #2295),
 
1050
         like in create_collection(), but mod_dav outsmarts us by just
 
1051
         returning the error when the node exists. */
 
1052
 
 
1053
      return dav_svn__convert_err(
 
1054
                  svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
 
1055
                                    "Path already exists, path '%s'",
 
1056
                                    comb->priv.repos_path),
 
1057
                  HTTP_METHOD_NOT_ALLOWED, NULL, pool);
 
1058
    }
 
1059
 
1037
1060
  return NULL;
1038
1061
}
1039
1062
 
1168
1191
 
1169
1192
  if (base->info->repos->root_path[1])
1170
1193
    comb->res.uri = apr_pstrcat(base->pool, base->info->repos->root_path,
1171
 
                                path->data, (char *)NULL);
 
1194
                                path->data, SVN_VA_NULL);
1172
1195
  else
1173
1196
    comb->res.uri = path->data;
1174
1197
  comb->res.info = &comb->priv;
1208
1231
 
1209
1232
 
1210
1233
AP_MODULE_DECLARE(dav_error *)
1211
 
dav_svn_split_uri(request_rec *r,
1212
 
                  const char *uri_to_split,
1213
 
                  const char *root_path,
1214
 
                  const char **cleaned_uri,
1215
 
                  int *trailing_slash,
1216
 
                  const char **repos_basename,
1217
 
                  const char **relative_path,
1218
 
                  const char **repos_path)
 
1234
dav_svn_split_uri2(request_rec *r,
 
1235
                   const char *uri_to_split,
 
1236
                   const char *root_path,
 
1237
                   const char **cleaned_uri,
 
1238
                   int *trailing_slash,
 
1239
                   const char **repos_basename,
 
1240
                   const char **relative_path,
 
1241
                   const char **repos_path,
 
1242
                   apr_pool_t *pool)
1219
1243
{
1220
1244
  apr_size_t len1;
1221
1245
  int had_slash;
1231
1255
  if ((fs_path == NULL) && (fs_parent_path == NULL))
1232
1256
    {
1233
1257
      /* ### are SVN_ERR_APMOD codes within the right numeric space? */
1234
 
      return dav_svn__new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
 
1258
      return dav_svn__new_error(pool, HTTP_INTERNAL_SERVER_ERROR,
1235
1259
                                SVN_ERR_APMOD_MISSING_PATH_TO_FS,
1236
1260
                                "The server is misconfigured: "
1237
1261
                                "either an SVNPath or SVNParentPath "
1240
1264
    }
1241
1265
 
1242
1266
  /* make a copy so that we can do some work on it */
1243
 
  uri = apr_pstrdup(r->pool, uri_to_split);
 
1267
  uri = apr_pstrdup(pool, uri_to_split);
1244
1268
 
1245
1269
  /* remove duplicate slashes, and make sure URI has no trailing '/' */
1246
1270
  ap_no2slash(uri);
1255
1279
    *trailing_slash = FALSE;
1256
1280
 
1257
1281
  /* return the first item.  */
1258
 
  *cleaned_uri = apr_pstrdup(r->pool, uri);
 
1282
  *cleaned_uri = apr_pstrdup(pool, uri);
1259
1283
 
1260
1284
  /* The URL space defined by the SVN provider is always a virtual
1261
1285
     space. Construct the path relative to the configured Location
1296
1320
  if (fs_path != NULL)
1297
1321
    {
1298
1322
      /* the repos_basename is the last component of root_path. */
1299
 
      *repos_basename = svn_dirent_basename(root_path, r->pool);
 
1323
      *repos_basename = svn_dirent_basename(root_path, pool);
1300
1324
 
1301
1325
      /* 'relative' is already correct for SVNPath; the root_path
1302
1326
         already contains the name of the repository, so relative is
1314
1338
      if (relative[1] == '\0')
1315
1339
        {
1316
1340
          /* ### are SVN_ERR_APMOD codes within the right numeric space? */
1317
 
          return dav_svn__new_error(r->pool, HTTP_FORBIDDEN,
 
1341
          return dav_svn__new_error(pool, HTTP_FORBIDDEN,
1318
1342
                                    SVN_ERR_APMOD_MALFORMED_URI,
1319
1343
                                    "The URI does not contain the name "
1320
1344
                                    "of a repository.");
1331
1355
        }
1332
1356
      else
1333
1357
        {
1334
 
          magic_component = apr_pstrndup(r->pool, relative + 1,
 
1358
          magic_component = apr_pstrndup(pool, relative + 1,
1335
1359
                                         magic_end - relative - 1);
1336
1360
          relative = magic_end;
1337
1361
        }
1341
1365
    }
1342
1366
 
1343
1367
  /* We can return 'relative' at this point too. */
1344
 
  *relative_path = apr_pstrdup(r->pool, relative);
 
1368
  *relative_path = apr_pstrdup(pool, relative);
1345
1369
 
1346
1370
  /* Code to remove the !svn junk from the front of the relative path,
1347
1371
     mainly stolen from parse_uri().  This code assumes that
1362
1386
        if (ch == '\0')
1363
1387
          {
1364
1388
            /* relative is just "!svn", which is malformed. */
1365
 
            return dav_svn__new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
 
1389
            return dav_svn__new_error(pool, HTTP_NOT_FOUND,
1366
1390
                                      SVN_ERR_APMOD_MALFORMED_URI,
1367
1391
                                      "Nothing follows the svn special_uri.");
1368
1392
          }
1389
1413
                          *repos_path = NULL;
1390
1414
                        else
1391
1415
                          return dav_svn__new_error(
1392
 
                                     r->pool, HTTP_INTERNAL_SERVER_ERROR,
 
1416
                                     pool, HTTP_NOT_FOUND,
1393
1417
                                     SVN_ERR_APMOD_MALFORMED_URI,
1394
1418
                                     "Missing info after special_uri.");
1395
1419
                      }
1413
1437
                            /* Did we break from the loop prematurely? */
1414
1438
                            if (j != (defn->numcomponents - 1))
1415
1439
                              return dav_svn__new_error(
1416
 
                                         r->pool, HTTP_INTERNAL_SERVER_ERROR,
 
1440
                                         pool, HTTP_NOT_FOUND,
1417
1441
                                         SVN_ERR_APMOD_MALFORMED_URI,
1418
1442
                                         "Not enough components after "
1419
1443
                                         "special_uri.");
1427
1451
                        else
1428
1452
                          {
1429
1453
                            /* Found a slash after the special components. */
1430
 
                            *repos_path = apr_pstrdup(r->pool, start);
 
1454
                            *repos_path = apr_pstrdup(pool, start - 1);
1431
1455
                          }
1432
1456
                      }
1433
1457
                    else
1434
1458
                      {
1435
1459
                        return
1436
 
                          dav_svn__new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
 
1460
                          dav_svn__new_error(pool, HTTP_NOT_FOUND,
1437
1461
                                        SVN_ERR_APMOD_MALFORMED_URI,
1438
1462
                                        "Unknown data after special_uri.");
1439
1463
                      }
1444
1468
 
1445
1469
            if (defn->name == NULL)
1446
1470
              return
1447
 
                dav_svn__new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR,
 
1471
                dav_svn__new_error(pool, HTTP_NOT_FOUND,
1448
1472
                                   SVN_ERR_APMOD_MALFORMED_URI,
1449
1473
                                   "Couldn't match subdir after special_uri.");
1450
1474
          }
1453
1477
      {
1454
1478
        /* There's no "!svn/" at all, so the relative path is already
1455
1479
           a valid path within the repository.  */
1456
 
        *repos_path = apr_pstrdup(r->pool, relative);
 
1480
        *repos_path = apr_pstrdup(pool, relative - 1);
1457
1481
      }
1458
1482
  }
1459
1483
 
1460
1484
  return NULL;
1461
1485
}
1462
1486
 
 
1487
AP_MODULE_DECLARE(dav_error *)
 
1488
dav_svn_split_uri(request_rec *r,
 
1489
                  const char *uri_to_split,
 
1490
                  const char *root_path,
 
1491
                  const char **cleaned_uri,
 
1492
                  int *trailing_slash,
 
1493
                  const char **repos_basename,
 
1494
                  const char **relative_path,
 
1495
                  const char **repos_path)
 
1496
{
 
1497
  return dav_svn_split_uri2(r, uri_to_split, root_path, cleaned_uri,
 
1498
                            trailing_slash, repos_basename, relative_path,
 
1499
                            repos_path, r->pool);
 
1500
}
1463
1501
 
1464
1502
/* Context for cleanup handler. */
1465
1503
struct cleanup_fs_access_baton
1530
1568
  if (r->uri[len-1] != '/')
1531
1569
    {
1532
1570
      new_uri = apr_pstrcat(r->pool, ap_escape_uri(r->pool, r->uri),
1533
 
                            "/", (char *)NULL);
 
1571
                            "/", SVN_VA_NULL);
1534
1572
      apr_table_setn(r->headers_out, "Location",
1535
1573
                     ap_construct_url(r->pool, new_uri, r));
1536
1574
      return dav_svn__new_error(r->pool, HTTP_MOVED_PERMANENTLY, 0,
1820
1858
                                      "Attempting to modify out-of-date resource.",
1821
1859
                                      r->pool);
1822
1860
        }
 
1861
      else if (comb->priv.version_name > created_rev)
 
1862
        {
 
1863
          svn_revnum_t txn_base_rev;
 
1864
 
 
1865
          txn_base_rev = svn_fs_txn_base_revision(comb->res.info->root.txn);
 
1866
          if (comb->priv.version_name > txn_base_rev)
 
1867
            {
 
1868
              serr = svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
 
1869
                                       "No such revision %ld",
 
1870
                                       comb->priv.version_name);
 
1871
 
 
1872
              return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
 
1873
                                          "Unknown base revision",
 
1874
                                          r->pool);
 
1875
            }
 
1876
        }
1823
1877
    }
1824
 
  else if (SVN_IS_VALID_REVNUM(comb->priv.version_name)
1825
 
           && comb->res.collection)
 
1878
  else if (comb->res.collection)
1826
1879
    {
1827
1880
      /* Issue #4480: With HTTPv2 we can receive the first change for a
1828
1881
         directory after it has been made mutable, because one of its
1837
1890
         properties changed since the BASE version.
1838
1891
 
1839
1892
         ### I think svn_fs_node_relation() checks for more changes than we
1840
 
             should check for here. Needs further review. But it looks like\
 
1893
             should check for here. Needs further review. But it looks like
1841
1894
             this check matches the checks in the libsvn_fs commit editor.
1842
1895
 
1843
1896
             For now I would say reporting out of date in a few too many
1846
1899
      svn_revnum_t txn_base_rev;
1847
1900
      svn_fs_root_t *txn_base_root;
1848
1901
      svn_fs_root_t *rev_root;
1849
 
      const svn_fs_id_t *txn_base_id;
1850
 
      const svn_fs_id_t *rev_id;
 
1902
      svn_fs_node_relation_t node_relation;
1851
1903
 
1852
1904
      txn_base_rev = svn_fs_txn_base_revision(comb->res.info->root.txn);
1853
1905
 
1856
1908
 
1857
1909
      serr = svn_fs_revision_root(&txn_base_root, comb->res.info->repos->fs,
1858
1910
                                  txn_base_rev, r->pool);
1859
 
                                  
1860
 
      if (!serr)
1861
 
        serr = svn_fs_node_id(&txn_base_id, txn_base_root,
1862
 
                              comb->priv.repos_path, r->pool);
1863
1911
 
1864
1912
      if (serr != NULL)
1865
1913
        {
1866
1914
          return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
1867
 
                                      "Could not open youngest revision root "
 
1915
                                      "Could not open the transaction revision "
1868
1916
                                      "for verification against the base "
1869
1917
                                      "revision", r->pool);
1870
1918
        }
1872
1920
      serr = svn_fs_revision_root(&rev_root, comb->res.info->repos->fs,
1873
1921
                                  comb->priv.version_name, r->pool);
1874
1922
 
1875
 
      if (!serr)
1876
 
        serr = svn_fs_node_id(&rev_id, rev_root,
1877
 
                              comb->priv.repos_path, r->pool);
1878
 
 
1879
1923
      if (serr != NULL)
1880
1924
        {
 
1925
          svn_fs_close_root(txn_base_root);
1881
1926
          return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
1882
 
                                      "Could not open the base revision"
1883
 
                                      "for verification against the youngest "
1884
 
                                      "revision", r->pool);
 
1927
                                      "Could not open the base revision "
 
1928
                                      "for verification against the "
 
1929
                                      "transaction revision", r->pool);
1885
1930
        }
1886
1931
 
 
1932
      serr = svn_fs_node_relation(&node_relation, rev_root,
 
1933
                                  comb->priv.repos_path,
 
1934
                                  txn_base_root,
 
1935
                                  comb->priv.repos_path,
 
1936
                                  r->pool);
 
1937
 
1887
1938
      svn_fs_close_root(rev_root);
1888
1939
      svn_fs_close_root(txn_base_root);
1889
1940
 
1890
 
      if (0 != svn_fs_compare_ids(txn_base_id, rev_id))
 
1941
      if (serr != NULL)
 
1942
        {
 
1943
          /* ### correct HTTP error? */
 
1944
          return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
 
1945
                                      "Unable to fetch the node revision id "
 
1946
                                      "of the version resource within the "
 
1947
                                      "revision",
 
1948
                                      r->pool);
 
1949
        }
 
1950
 
 
1951
      if (node_relation != svn_fs_node_unchanged)
1891
1952
        {
1892
1953
          serr = svn_error_createf(SVN_ERR_RA_OUT_OF_DATE, NULL,
1893
1954
                                   "Directory '%s' is out of date",
2065
2126
  xslt_uri = dav_svn__get_xslt_uri(r);
2066
2127
  fs_parent_path = dav_svn__get_fs_parent_path(r);
2067
2128
 
 
2129
  if (r->method_number == M_COPY)
 
2130
    {
 
2131
      /* Workaround for issue #4531: Avoid a depth-infinity walk on
 
2132
         the copy source by overriding the Depth header here.
 
2133
         mod_dav defaults to infinite depth if this header is not set
 
2134
         which makes copies O(size of source) rather than the desired O(1).
 
2135
         ### Should be fixed by an explicit provider API feature in mod_dav. */
 
2136
      apr_table_setn(r->headers_in, "Depth", "0");
 
2137
    }
 
2138
 
2068
2139
  /* Special case: detect and build the SVNParentPath as a unique type
2069
2140
     of private resource, iff the SVNListParentPath directive is 'on'. */
2070
2141
  if (dav_svn__is_parentpath_list(r))
2261
2332
  }
2262
2333
 
2263
2334
  /* Retrieve/cache open repository */
2264
 
  repos_key = apr_pstrcat(r->pool, "mod_dav_svn:", fs_path, (char *)NULL);
 
2335
  repos_key = apr_pstrcat(r->pool, "mod_dav_svn:", fs_path, SVN_VA_NULL);
2265
2336
  apr_pool_userdata_get(&userdata, repos_key, r->connection->pool);
2266
2337
  repos->repos = userdata;
2267
2338
  if (repos->repos == NULL)
2275
2346
      svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS,
2276
2347
                    dav_svn__get_fulltext_cache_flag(r) ? "1" :"0");
2277
2348
      svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS,
2278
 
                    dav_svn__get_revprop_cache_flag(r) ? "1" :"0");
 
2349
                    dav_svn__get_revprop_cache_flag(r) ? "2" :"0");
 
2350
      svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_BLOCK_READ,
 
2351
                    dav_svn__get_block_read_flag(r) ? "1" :"0");
2279
2352
 
2280
2353
      /* Disallow BDB/event until issue 4157 is fixed. */
2281
2354
      if (!strcmp(ap_show_mpm(), "event"))
2298
2371
 
2299
2372
      /* open the FS */
2300
2373
      if (!serr)
2301
 
        serr = svn_repos_open2(&(repos->repos), fs_path, fs_config,
2302
 
                               r->connection->pool);
 
2374
        serr = svn_repos_open3(&(repos->repos), fs_path, fs_config,
 
2375
                               r->connection->pool, r->pool);
2303
2376
      if (serr != NULL)
2304
2377
        {
2305
2378
          /* The error returned by svn_repos_open2 might contain the
2307
2380
             leak that path back to the client, because that would be
2308
2381
             a security risk, but we do want to log the real error on
2309
2382
             the server side. */
2310
 
          return dav_svn__sanitize_error(serr, "Could not open the requested "
2311
 
                                         "SVN filesystem",
2312
 
                                         HTTP_INTERNAL_SERVER_ERROR, r);
 
2383
 
 
2384
          apr_status_t cause = svn_error_root_cause(serr)->apr_err;
 
2385
          if (APR_STATUS_IS_ENOENT(cause) || APR_STATUS_IS_ENOTDIR(cause))
 
2386
            return dav_svn__sanitize_error(
 
2387
                serr, "Could not find the requested SVN filesystem",
 
2388
                HTTP_NOT_FOUND, r);
 
2389
          else
 
2390
            return dav_svn__sanitize_error(
 
2391
                serr, "Could not open the requested SVN filesystem",
 
2392
                HTTP_INTERNAL_SERVER_ERROR, r);
2313
2393
        }
2314
2394
 
2315
2395
      /* Cache the open repos for the next request on this connection */
2467
2547
                                         "/",
2468
2548
                                         r->args ? "?" : "",
2469
2549
                                         r->args ? r->args : "",
2470
 
                                         (char *)NULL);
 
2550
                                         SVN_VA_NULL);
2471
2551
      apr_table_setn(r->headers_out, "Location",
2472
2552
                     ap_construct_url(r->pool, new_path, r));
2473
2553
      return dav_svn__new_error(r->pool, HTTP_MOVED_PERMANENTLY, 0,
3471
3551
          /* ### The xml output doesn't like to see a trailing slash on
3472
3552
             ### the visible portion, so avoid that. */
3473
3553
          if (is_dir)
3474
 
            href = apr_pstrcat(entry_pool, href, "/", (char *)NULL);
 
3554
            href = apr_pstrcat(entry_pool, href, "/", SVN_VA_NULL);
3475
3555
 
3476
3556
          if (gen_html)
3477
3557
            name = href;
3723
3803
                                    resource->info->repos->base_url,
3724
3804
                                    ap_escape_uri(resource->pool,
3725
3805
                                                  resource->info->r->uri),
3726
 
                                    NULL);
 
3806
                                    SVN_VA_NULL);
3727
3807
              str_root = apr_pstrcat(resource->pool,
3728
3808
                                     resource->info->repos->base_url,
3729
3809
                                     resource->info->repos->root_path,
3730
 
                                     NULL);
 
3810
                                     SVN_VA_NULL);
3731
3811
 
3732
3812
              serr = svn_subst_build_keywords3(&kw, keywords->data,
3733
3813
                                               str_cmt_rev, str_uri, str_root,
3754
3834
        apr_size_t bufsize = SVN__STREAM_CHUNK_SIZE;
3755
3835
 
3756
3836
        /* read from the FS ... */
3757
 
        serr = svn_stream_read(stream, block, &bufsize);
 
3837
        serr = svn_stream_read_full(stream, block, &bufsize);
3758
3838
        if (serr != NULL)
3759
3839
          {
3760
3840
            return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
3904
3984
        return err;
3905
3985
    }
3906
3986
 
3907
 
  serr = svn_dirent_get_absolute(&src_repos_path,
3908
 
                                 svn_repos_path(src->info->repos->repos,
3909
 
                                                src->pool),
3910
 
                                 src->pool);
3911
 
  if (!serr)
3912
 
    serr = svn_dirent_get_absolute(&dst_repos_path,
3913
 
                                   svn_repos_path(dst->info->repos->repos,
3914
 
                                                  dst->pool),
3915
 
                                   dst->pool);
3916
 
 
3917
 
  if (!serr)
3918
 
    {
3919
 
      if (strcmp(src_repos_path, dst_repos_path) != 0)
3920
 
        return dav_svn__new_error_tag
3921
 
          (dst->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
3922
 
           "Copy source and destination are in different repositories.",
3923
 
           SVN_DAV_ERROR_NAMESPACE, SVN_DAV_ERROR_TAG);
 
3987
  src_repos_path = svn_repos_path(src->info->repos->repos, src->pool);
 
3988
  dst_repos_path = svn_repos_path(dst->info->repos->repos, dst->pool);
 
3989
 
 
3990
  if (strcmp(src_repos_path, dst_repos_path) != 0)
 
3991
    {
 
3992
      /* Perhaps the source and dst repos use different path formats? */
 
3993
      serr = svn_error_compose_create(
 
3994
                svn_dirent_get_absolute(&src_repos_path, src_repos_path,
 
3995
                                        src->pool),
 
3996
                svn_dirent_get_absolute(&dst_repos_path, dst_repos_path,
 
3997
                                        dst->pool));
 
3998
 
 
3999
      if (!serr && (strcmp(src_repos_path, dst_repos_path) != 0))
 
4000
          return dav_svn__new_error_svn(
 
4001
                dst->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
 
4002
                "Copy source and destination are in different repositories");
 
4003
    }
 
4004
  else
 
4005
      serr = SVN_NO_ERROR;
 
4006
 
 
4007
  if (!serr)
 
4008
    {
3924
4009
      serr = svn_fs_copy(src->info->root.root,  /* root object of src rev*/
3925
4010
                         src->info->repos_path, /* relative path of src */
3926
4011
                         dst->info->root.root,  /* root object of dst txn*/
4030
4115
      if (resource->info->version_name < created_rev)
4031
4116
        {
4032
4117
          serr = svn_error_createf(SVN_ERR_RA_OUT_OF_DATE, NULL,
4033
 
                                   "Item '%s' is out of date",
 
4118
                                   resource->collection
 
4119
                                    ? "Directory '%s' is out of date"
 
4120
                                    : (resource->exists
 
4121
                                        ? "File '%s' is out of date"
 
4122
                                        : "'%s' is out of date"),
4034
4123
                                   resource->info->repos_path);
4035
4124
          return dav_svn__convert_err(serr, HTTP_CONFLICT,
4036
4125
                                      "Can't DELETE out-of-date resource",
4042
4131
     incoming lock-tokens into the filesystem's access_t.  Normally
4043
4132
     they come in via 'If:' header, and get_resource()
4044
4133
     automatically notices them and does this work for us.  In the
4045
 
     case of a directory deletion, however, svn clients are sending
4046
 
     'child' lock-tokens in the DELETE request body. */
 
4134
     case of a directory deletion, however, older subversion clients
 
4135
     are sending 'child' lock-tokens in the non-standard DELETE
 
4136
     request body. */
4047
4137
 
4048
4138
  err = dav_svn__build_lock_hash(&locks, resource->info->r,
4049
4139
                                 resource->info->repos_path, resource->pool);
4157
4247
 
4158
4248
} walker_ctx_t;
4159
4249
 
4160
 
 
 
4250
/* Recursively walk a resource for walk().  When DEPTH != 0, recurse with
 
4251
   DEPTH-1 on child nodes. WALK_ROOT should be TRUE for the root and will be
 
4252
   FALSE for any descendants, to avoid unneeded work for every descendant
 
4253
   node.
 
4254
   */
4161
4255
static dav_error *
4162
4256
do_walk(walker_ctx_t *ctx,
4163
4257
        int depth,
 
4258
        svn_boolean_t walk_root,
4164
4259
        apr_pool_t *scratch_pool)
4165
4260
{
4166
4261
  const dav_walk_params *params = ctx->params;
4225
4320
  uri_len = ctx->uri->len;
4226
4321
  repos_len = ctx->repos_path->len;
4227
4322
 
4228
 
  /* Tell our logging subsystem that we're listing a directory.
 
4323
  if (walk_root)
 
4324
    {
 
4325
      /* Tell our logging subsystem that we're listing a directory.
4229
4326
 
4230
 
     Note: if we cared, we could look at the 'User-Agent:' request
4231
 
     header and distinguish an svn client ('svn ls') from a generic
4232
 
     DAV client.  */
4233
 
  dav_svn__operational_log(&ctx->info,
4234
 
                           svn_log__get_dir(ctx->info.repos_path,
4235
 
                                            ctx->info.root.rev,
4236
 
                                            TRUE, FALSE, SVN_DIRENT_ALL,
4237
 
                                            scratch_pool));
 
4327
      Note: if we cared, we could look at the 'User-Agent:' request
 
4328
         header and distinguish an svn client ('svn ls') from a generic
 
4329
         DAV client.  */
 
4330
      dav_svn__operational_log(&ctx->info,
 
4331
                               svn_log__get_dir(ctx->info.repos_path,
 
4332
                                                ctx->info.root.rev,
 
4333
                                                TRUE, FALSE, SVN_DIRENT_ALL,
 
4334
                                                scratch_pool));
 
4335
    }
4238
4336
 
4239
4337
  /* fetch this collection's children */
4240
4338
  serr = svn_fs_dir_entries(&children, ctx->info.root.root,
4267
4365
                        apr_pstrmemdup(iterpool,
4268
4366
                                       ctx->repos_path->data,
4269
4367
                                       ctx->repos_path->len),
4270
 
                        key, (char *)NULL);
 
4368
                        key, SVN_VA_NULL);
4271
4369
          if (! dav_svn__allow_read(ctx->info.r, ctx->info.repos,
4272
4370
                                    repos_relpath, ctx->info.root.rev,
4273
4371
                                    iterpool))
4287
4385
        {
4288
4386
          err = (*params->func)(&ctx->wres, DAV_CALLTYPE_MEMBER);
4289
4387
          if (err != NULL)
4290
 
            return err;
 
4388
            {
 
4389
              svn_pool_destroy(iterpool);
 
4390
              return err;
 
4391
            }
4291
4392
        }
4292
4393
      else
4293
4394
        {
4299
4400
          ctx->res.uri = ctx->uri->data;
4300
4401
 
4301
4402
          /* recurse on this collection */
4302
 
          err = do_walk(ctx, depth - 1, iterpool);
 
4403
          err = do_walk(ctx, depth - 1, FALSE, iterpool);
4303
4404
          if (err != NULL)
4304
 
            return err;
 
4405
            {
 
4406
              svn_pool_destroy(iterpool);
 
4407
              return err;
 
4408
            }
4305
4409
 
4306
4410
          /* restore the data */
4307
4411
          ctx->res.collection = FALSE;
4381
4485
  /* ### is the root already/always open? need to verify */
4382
4486
 
4383
4487
  /* always return the error, and any/all multistatus responses */
4384
 
  err = do_walk(&ctx, depth, params->pool);
 
4488
  err = do_walk(&ctx, depth, TRUE, params->pool);
4385
4489
  *response = ctx.wres.response;
4386
4490
 
4387
4491
  return err;
4428
4532
 
4429
4533
  if (base->info->repos->root_path[1])
4430
4534
    res->uri = apr_pstrcat(base->pool, base->info->repos->root_path,
4431
 
                           path, (char *)NULL);
 
4535
                           path, SVN_VA_NULL);
4432
4536
  else
4433
4537
    res->uri = path;
4434
4538
  res->hooks = &dav_svn__hooks_repository;
4481
4585
      /* if rev was specific, create baseline-collection URL */
4482
4586
      path = dav_svn__build_uri(repos, DAV_SVN__BUILD_URI_BC,
4483
4587
                                priv->root.rev, priv->repos_path,
4484
 
                                0, resource->pool);
 
4588
                                FALSE /* add_href */, resource->pool);
4485
4589
    }
4486
4590
  path = svn_path_uri_encode(path, resource->pool);
4487
4591
  priv->uri_path = svn_stringbuf_create(path, resource->pool);