4
4
* ====================================================================
5
* Copyright (c) 2000-2008 CollabNet. All rights reserved.
7
* This software is licensed as described in the file COPYING, which
8
* you should have received as part of this distribution. The terms
9
* are also available at http://subversion.tigris.org/license-1.html.
10
* If newer versions of this license are posted there, you may use a
11
* newer version instead, at your option.
13
* This software consists of voluntary contributions made by many
14
* individuals. For exact contribution history, see the revision
15
* history and logs, available at http://subversion.tigris.org/.
5
* Licensed to the Apache Software Foundation (ASF) under one
6
* or more contributor license agreements. See the NOTICE file
7
* distributed with this work for additional information
8
* regarding copyright ownership. The ASF licenses this file
9
* to you under the Apache License, Version 2.0 (the
10
* "License"); you may not use this file except in compliance
11
* with the License. You may obtain a copy of the License at
13
* http://www.apache.org/licenses/LICENSE-2.0
15
* Unless required by applicable law or agreed to in writing,
16
* software distributed under the License is distributed on an
17
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18
* KIND, either express or implied. See the License for the
19
* specific language governing permissions and limitations
16
21
* ====================================================================
619
624
SVN_ERR(svn_fs_copied_from(©_src_rev, ©_src_path,
620
625
copy_root, copy_path, pool));
621
626
if (! strcmp(copy_path, path) == 0)
622
remainder = svn_path_is_child(copy_path, path, pool);
627
remainder = svn_fspath__is_child(copy_path, path, pool);
624
*prev_path = svn_path_join(copy_src_path, remainder, pool);
629
*prev_path = svn_fspath__join(copy_src_path, remainder, pool);
625
630
if (appeared_rev)
626
631
*appeared_rev = svn_fs_revision_root_revision(copy_root);
635
640
apr_hash_t **locations,
636
641
const char *fs_path,
637
642
svn_revnum_t peg_revision,
638
apr_array_header_t *location_revisions_orig,
643
const apr_array_header_t *location_revisions_orig,
639
644
svn_repos_authz_func_t authz_read_func,
640
645
void *authz_read_baton,
641
646
apr_pool_t *pool)
654
659
/* Ensure that FS_PATH is absolute, because our path-math below will
655
660
depend on that being the case. */
656
661
if (*fs_path != '/')
657
fs_path = apr_pstrcat(pool, "/", fs_path, NULL);
662
fs_path = apr_pstrcat(pool, "/", fs_path, (char *)NULL);
659
664
/* Another sanity check. */
660
665
if (authz_read_func)
868
876
/* Ensure that PATH is absolute, because our path-math will depend
869
877
on that being the case. */
870
878
if (*path != '/')
871
path = apr_pstrcat(pool, "/", path, NULL);
879
path = apr_pstrcat(pool, "/", path, (char *)NULL);
873
881
/* Auth check. */
874
882
if (authz_read_func)
933
941
/* authz_read_func requires path to have a leading slash. */
934
942
const char *abs_path = apr_pstrcat(subpool, "/", segment->path,
937
945
SVN_ERR(svn_fs_revision_root(&cur_rev_root, fs,
938
946
segment->range_end, subpool));
1056
1064
APR_HASH_KEY_STRING);
1057
1065
if (changed_path && changed_path->prop_mod)
1059
if (svn_dirent_is_root(path, strlen(path)))
1067
if (svn_fspath__is_root(path, strlen(path)))
1061
1069
svn_pool_destroy(subpool);
1062
1070
*merged_mergeinfo = NULL;
1063
1071
return SVN_NO_ERROR;
1065
path = svn_path_dirname(path, subpool);
1073
path = svn_fspath__dirname(path, subpool);
1068
1076
/* First, find the mergeinfo difference for old_path_rev->revnum, and
1069
1077
old_path_rev->revnum - 1. */
1070
SVN_ERR(get_path_mergeinfo(&curr_mergeinfo, repos->fs, old_path_rev->path,
1071
old_path_rev->revnum, subpool));
1078
err = get_path_mergeinfo(&curr_mergeinfo, repos->fs, old_path_rev->path,
1079
old_path_rev->revnum, subpool);
1082
if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
1084
/* Issue #3896: If invalid mergeinfo is encountered the
1085
best we can do is ignore it and act is if there are
1086
no mergeinfo differences. */
1087
svn_error_clear(err);
1088
svn_pool_destroy(subpool);
1089
*merged_mergeinfo = NULL;
1090
return SVN_NO_ERROR;
1094
return svn_error_trace(err);
1072
1098
err = get_path_mergeinfo(&prev_mergeinfo, repos->fs, old_path_rev->path,
1073
1099
old_path_rev->revnum - 1, subpool);
1074
if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
1100
if (err && (err->apr_err == SVN_ERR_FS_NOT_FOUND
1101
|| err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR))
1076
/* If the path doesn't exist in the previous revision, assume no
1103
/* If the path doesn't exist in the previous revision or it does exist
1104
but has invalid mergeinfo (Issue #3896), assume no merges. */
1078
1105
svn_error_clear(err);
1079
1106
svn_pool_destroy(subpool);
1080
1107
*merged_mergeinfo = NULL;
1086
1113
/* Then calculate and merge the differences. */
1087
1114
SVN_ERR(svn_mergeinfo_diff(&deleted, &changed, prev_mergeinfo, curr_mergeinfo,
1088
1115
FALSE, subpool));
1089
if (apr_hash_count(deleted))
1090
SVN_ERR(svn_mergeinfo_merge(changed, deleted, subpool));
1116
SVN_ERR(svn_mergeinfo_merge(changed, deleted, subpool));
1092
1118
/* Store the result. */
1093
1119
if (apr_hash_count(changed))
1211
1237
compare_path_revisions(const void *a, const void *b)
1213
struct path_revision *a_pr = *(struct path_revision **)a;
1214
struct path_revision *b_pr = *(struct path_revision **)b;
1239
struct path_revision *a_pr = *(struct path_revision *const *)a;
1240
struct path_revision *b_pr = *(struct path_revision *const *)b;
1216
1242
if (a_pr->revnum == b_pr->revnum)
1222
1248
static svn_error_t *
1223
1249
find_merged_revisions(apr_array_header_t **merged_path_revisions_out,
1224
apr_array_header_t *mainline_path_revisions,
1251
const apr_array_header_t *mainline_path_revisions,
1225
1252
svn_repos_t *repos,
1226
1253
apr_hash_t *duplicate_path_revs,
1227
1254
svn_repos_authz_func_t authz_read_func,
1228
1255
void *authz_read_baton,
1229
1256
apr_pool_t *pool)
1231
apr_array_header_t *old, *new;
1258
const apr_array_header_t *old;
1259
apr_array_header_t *new_merged_path_revs;
1232
1260
apr_pool_t *iterpool, *last_pool;
1233
apr_array_header_t *merged_path_revisions = apr_array_make(pool, 0,
1234
sizeof(struct path_revision *));
1261
apr_array_header_t *merged_path_revisions =
1262
apr_array_make(pool, 0, sizeof(struct path_revision *));
1236
1264
old = mainline_path_revisions;
1237
1265
iterpool = svn_pool_create(pool);
1243
1271
apr_pool_t *temp_pool;
1245
1273
svn_pool_clear(iterpool);
1246
new = apr_array_make(iterpool, 0, sizeof(struct path_revision *));
1274
new_merged_path_revs = apr_array_make(iterpool, 0,
1275
sizeof(struct path_revision *));
1248
1277
/* Iterate over OLD, checking for non-empty mergeinfo. If found, gather
1249
1278
path_revisions for any merged revisions, and store those in NEW. */
1279
1308
svn_node_kind_t kind;
1280
1309
svn_fs_root_t *root;
1311
if (range->end < start)
1282
1314
svn_pool_clear(iterpool3);
1283
1316
SVN_ERR(svn_fs_revision_root(&root, repos->fs, range->end,
1285
1318
SVN_ERR(svn_fs_check_path(&kind, root, path, iterpool3));
1289
1322
/* Search and find revisions to add to the NEW list. */
1290
SVN_ERR(find_interesting_revisions(new, repos, path,
1323
SVN_ERR(find_interesting_revisions(new_merged_path_revs,
1291
1325
range->start, range->end,
1293
1327
duplicate_path_revs,
1303
1337
/* Append the newly found path revisions with the old ones. */
1304
1338
merged_path_revisions = apr_array_append(iterpool, merged_path_revisions,
1339
new_merged_path_revs);
1307
1341
/* Swap data structures */
1342
old = new_merged_path_revs;
1309
1343
temp_pool = last_pool;
1310
1344
last_pool = iterpool;
1311
1345
iterpool = temp_pool;
1313
while (new->nelts > 0);
1347
while (new_merged_path_revs->nelts > 0);
1315
1349
/* Sort MERGED_PATH_REVISIONS in increasing order by REVNUM. */
1316
1350
qsort(merged_path_revisions->elts, merged_path_revisions->nelts,
1353
1387
apr_pool_t *tmp_pool; /* For swapping */
1354
1388
svn_boolean_t contents_changed;
1356
svn_pool_clear(sb->iter_pool);
1390
svn_pool_clear(sb->iterpool);
1358
1392
/* Get the revision properties. */
1359
1393
SVN_ERR(svn_fs_revision_proplist(&rev_props, repos->fs,
1360
path_rev->revnum, sb->iter_pool));
1394
path_rev->revnum, sb->iterpool));
1362
1396
/* Open the revision root. */
1363
1397
SVN_ERR(svn_fs_revision_root(&root, repos->fs, path_rev->revnum,
1366
1400
/* Get the file's properties for this revision and compute the diffs. */
1367
1401
SVN_ERR(svn_fs_node_proplist(&props, root, path_rev->path,
1369
1403
SVN_ERR(svn_prop_diffs(&prop_diffs, props, sb->last_props,
1372
1406
/* Check if the contents changed. */
1373
1407
/* Special case: In the first revision, we always provide a delta. */
1374
1408
if (sb->last_root)
1375
1409
SVN_ERR(svn_fs_contents_changed(&contents_changed, sb->last_root,
1376
1410
sb->last_path, root, path_rev->path,
1379
1413
contents_changed = TRUE;
1383
1417
rev_props, path_rev->merged,
1384
1418
contents_changed ? &delta_handler : NULL,
1385
1419
contents_changed ? &delta_baton : NULL,
1386
prop_diffs, sb->iter_pool));
1420
prop_diffs, sb->iterpool));
1388
1422
/* Compute and send delta if client asked for it.
1389
1423
Note that this was initialized to NULL, so if !contents_changed,
1394
1428
SVN_ERR(svn_fs_get_file_delta_stream(&delta_stream,
1395
1429
sb->last_root, sb->last_path,
1396
1430
root, path_rev->path,
1398
1432
/* And send. */
1399
1433
SVN_ERR(svn_txdelta_send_txstream(delta_stream,
1400
1434
delta_handler, delta_baton,
1404
1438
/* Remember root, path and props for next iteration. */
1461
1495
/* If we are including merged revisions, go get those, too. */
1462
1496
if (include_merged_revisions)
1463
SVN_ERR(find_merged_revisions(&merged_path_revisions,
1497
SVN_ERR(find_merged_revisions(&merged_path_revisions, start,
1464
1498
mainline_path_revisions, repos,
1465
1499
duplicate_path_revs, authz_read_func,
1466
1500
authz_read_baton, pool));
1474
1508
/* We switch betwwen two pools while looping, since we need information from
1475
1509
the last iteration to be available. */
1476
sb.iter_pool = svn_pool_create(pool);
1510
sb.iterpool = svn_pool_create(pool);
1477
1511
sb.last_pool = svn_pool_create(pool);
1479
1513
/* We want the first txdelta to be against the empty file. */