2
2
* reporter.c : `reporter' vtable routines for updates.
4
4
* ====================================================================
5
* Copyright (c) 2000-2006, 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
* ====================================================================
24
#include "svn_dirent_uri.h"
19
25
#include "svn_path.h"
20
26
#include "svn_types.h"
21
27
#include "svn_error.h"
77
85
apr_pool_t *pool; /* Container pool */
88
/* Describes the standard revision properties that are relevant for
89
reports. Since a particular revision will often show up more than
90
once in the report, we cache these properties for the time of the
92
typedef struct revision_info_t
94
svn_revnum_t rev; /* revision number */
95
svn_string_t* date; /* revision timestamp */
96
svn_string_t* author; /* name of the revisions' author */
80
99
/* A structure used by the routines within the `reporter' vtable,
81
100
driven by the client as it describes its working copy revisions. */
82
101
typedef struct report_baton_t
84
103
/* Parameters remembered from svn_repos_begin_report2 */
85
104
svn_repos_t *repos;
86
const char *fs_base; /* FS path corresponding to wc anchor */
87
const char *s_operand; /* Anchor-relative wc target (may be empty) */
105
const char *fs_base; /* fspath corresponding to wc anchor */
106
const char *s_operand; /* anchor-relative wc target (may be empty) */
88
107
svn_revnum_t t_rev; /* Revnum which the edit will bring the wc to */
89
108
const char *t_path; /* FS path the edit will bring the wc to */
90
109
svn_boolean_t text_deltas; /* Whether to report text deltas */
161
186
len + 1 wraps around and we end up passing 0 to apr_palloc(),
162
187
thus getting a pointer to no storage? Probably not (16 exabyte
163
188
string, anyone?) but let's be future-proof anyway. */
189
if (len + 1 < len || len + 1 > APR_SIZE_MAX)
166
191
/* xgettext doesn't expand preprocessor definitions, so we must
167
192
pass translatable string to apr_psprintf() function to create
177
buf = apr_palloc(pool, len + 1);
178
SVN_ERR(svn_io_file_read_full(temp, buf, len, NULL, pool));
202
size = (apr_size_t)len;
203
buf = apr_palloc(pool, size+1);
204
SVN_ERR(svn_io_file_read_full2(temp, buf, size, NULL, NULL, pool));
181
207
return SVN_NO_ERROR;
419
445
return b->editor->change_file_prop(file_baton, name, value, pool);
448
/* For the report B, return the relevant revprop data of revision REV in
449
REVISION_INFO. The revision info will be allocated in b->pool.
450
Temporaries get allocated on SCRATCH_POOL. */
452
get_revision_info(report_baton_t *b,
454
revision_info_t** revision_info,
455
apr_pool_t *scratch_pool)
458
svn_string_t *cdate, *author;
459
revision_info_t* info;
461
/* Try to find the info in the report's cache */
462
info = apr_hash_get(b->revision_infos, &rev, sizeof(rev));
465
/* Info is not available, yet.
467
SVN_ERR(svn_fs_revision_proplist(&r_props,
472
/* Extract the committed-date. */
473
cdate = apr_hash_get(r_props, SVN_PROP_REVISION_DATE,
474
APR_HASH_KEY_STRING);
476
/* Extract the last-author. */
477
author = apr_hash_get(r_props, SVN_PROP_REVISION_AUTHOR,
478
APR_HASH_KEY_STRING);
480
/* Create a result object */
481
info = apr_palloc(b->pool, sizeof(*info));
483
info->date = cdate ? svn_string_dup(cdate, b->pool) : NULL;
484
info->author = author ? svn_string_dup(author, b->pool) : NULL;
487
apr_hash_set(b->revision_infos, &info->rev, sizeof(rev), info);
490
*revision_info = info;
422
495
/* Generate the appropriate property editing calls to turn the
423
496
properties of S_REV/S_PATH into those of B->t_root/T_PATH. If
424
497
S_PATH is NULL, this is an add, so assume the target starts with no
431
504
void *object, apr_pool_t *pool)
433
506
svn_fs_root_t *s_root;
434
apr_hash_t *s_props, *t_props, *r_props;
507
apr_hash_t *s_props, *t_props;
435
508
apr_array_header_t *prop_diffs;
437
510
svn_revnum_t crev;
438
511
const char *uuid;
439
svn_string_t *cr_str, *cdate, *last_author;
512
svn_string_t *cr_str;
513
revision_info_t* revision_info;
440
514
svn_boolean_t changed;
441
515
const svn_prop_t *pc;
442
516
svn_lock_t *lock;
450
524
SVN_ERR(change_fn(b, object,
451
525
SVN_PROP_ENTRY_COMMITTED_REV, cr_str, pool));
453
SVN_ERR(svn_fs_revision_proplist(&r_props, b->repos->fs, crev, pool));
527
SVN_ERR(get_revision_info(b, crev, &revision_info, pool));
455
529
/* Transmit the committed-date. */
456
cdate = apr_hash_get(r_props, SVN_PROP_REVISION_DATE,
457
APR_HASH_KEY_STRING);
530
if (revision_info->date || s_path)
459
531
SVN_ERR(change_fn(b, object, SVN_PROP_ENTRY_COMMITTED_DATE,
532
revision_info->date, pool));
462
534
/* Transmit the last-author. */
463
last_author = apr_hash_get(r_props, SVN_PROP_REVISION_AUTHOR,
464
APR_HASH_KEY_STRING);
465
if (last_author || s_path)
535
if (revision_info->author || s_path)
466
536
SVN_ERR(change_fn(b, object, SVN_PROP_ENTRY_LAST_AUTHOR,
537
revision_info->author, pool));
469
539
/* Transmit the UUID. */
470
540
SVN_ERR(svn_fs_get_uuid(b->repos->fs, &uuid, pool));
601
671
ent = apr_palloc(pool, sizeof(**entry));
602
ent->name = svn_path_basename(path, pool);
672
/* ### All callers should be updated to pass just one of these
674
ent->name = (*path == '/') ? svn_fspath__basename(path, pool)
675
: svn_relpath_basename(path, pool);
603
676
SVN_ERR(svn_fs_node_id(&ent->id, root, path, pool));
604
677
ent->kind = kind;
668
741
starting with '/', so make sure o_path always starts with a '/'
670
743
if (*o_path != '/')
671
o_path = apr_pstrcat(pool, "/", o_path, NULL);
744
o_path = apr_pstrcat(pool, "/", o_path, (char *)NULL);
673
746
SVN_ERR(svn_fs_closest_copy(&closest_copy_root, &closest_copy_path,
674
747
b->t_root, o_path, pool));
787
859
if (s_entry && t_entry && s_entry->kind == t_entry->kind)
789
distance = svn_fs_compare_ids(s_entry->id, t_entry->id);
861
int distance = svn_fs_compare_ids(s_entry->id, t_entry->id);
790
862
if (distance == 0 && !any_path_info(b, e_path)
791
863
&& (requested_depth <= wc_depth || t_entry->kind == svn_node_file))
956
1027
apr_hash_t *s_entries = NULL, *t_entries;
957
1028
apr_hash_index_t *hi;
958
1029
apr_pool_t *subpool;
959
const svn_fs_dirent_t *s_entry, *t_entry;
961
1030
const char *name, *s_fullpath, *t_fullpath, *e_fullpath;
962
1031
path_info_t *info;
1056
const svn_fs_dirent_t *s_entry, *t_entry;
987
1058
svn_pool_clear(subpool);
988
1059
SVN_ERR(fetch_path_info(b, &name, &info, e_path, subpool));
1008
e_fullpath = svn_path_join(e_path, name, subpool);
1009
t_fullpath = svn_path_join(t_path, name, subpool);
1079
e_fullpath = svn_relpath_join(e_path, name, subpool);
1080
t_fullpath = svn_fspath__join(t_path, name, subpool);
1010
1081
t_entry = apr_hash_get(t_entries, name, APR_HASH_KEY_STRING);
1011
s_fullpath = s_path ? svn_path_join(s_path, name, subpool) : NULL;
1082
s_fullpath = s_path ? svn_fspath__join(s_path, name, subpool) : NULL;
1012
1083
s_entry = s_entries ?
1013
1084
apr_hash_get(s_entries, name, APR_HASH_KEY_STRING) : NULL;
1053
1124
hi = apr_hash_next(hi))
1126
const svn_fs_dirent_t *s_entry;
1055
1128
svn_pool_clear(subpool);
1056
apr_hash_this(hi, NULL, NULL, &val);
1129
s_entry = svn__apr_hash_index_val(hi);
1059
1131
if (apr_hash_get(t_entries, s_entry->name,
1060
1132
APR_HASH_KEY_STRING) == NULL)
1073
1145
/* There is no corresponding target entry, so delete. */
1074
e_fullpath = svn_path_join(e_path, s_entry->name, subpool);
1146
e_fullpath = svn_relpath_join(e_path, s_entry->name, subpool);
1075
1147
SVN_ERR(svn_repos_deleted_rev(svn_fs_root_fs(b->t_root),
1076
svn_path_join(t_path,
1148
svn_fspath__join(t_path,
1079
1151
s_rev, b->t_rev,
1080
1152
&deleted_rev, subpool));
1089
1161
/* Loop over the dirents in the target. */
1090
1162
for (hi = apr_hash_first(pool, t_entries); hi; hi = apr_hash_next(hi))
1164
const svn_fs_dirent_t *s_entry, *t_entry;
1092
1166
svn_pool_clear(subpool);
1093
apr_hash_this(hi, NULL, NULL, &val);
1167
t_entry = svn__apr_hash_index_val(hi);
1096
1169
if (is_depth_upgrade(wc_depth, requested_depth, t_entry->kind))
1118
1191
apr_hash_get(s_entries, t_entry->name, APR_HASH_KEY_STRING)
1120
1193
s_fullpath = s_entry ?
1121
svn_path_join(s_path, t_entry->name, subpool) : NULL;
1194
svn_fspath__join(s_path, t_entry->name, subpool) : NULL;
1124
1197
/* Compose the report, editor, and target paths for this entry. */
1125
e_fullpath = svn_path_join(e_path, t_entry->name, subpool);
1126
t_fullpath = svn_path_join(t_path, t_entry->name, subpool);
1198
e_fullpath = svn_relpath_join(e_path, t_entry->name, subpool);
1199
t_fullpath = svn_fspath__join(t_path, t_entry->name, subpool);
1128
1201
SVN_ERR(update_entry(b, s_rev, s_fullpath, s_entry, t_fullpath,
1129
1202
t_entry, dir_baton, e_fullpath, NULL,
1152
1225
/* Compute the target path corresponding to the working copy anchor,
1153
1226
and check its authorization. */
1154
t_anchor = *b->s_operand ? svn_path_dirname(b->t_path, pool) : b->t_path;
1227
t_anchor = *b->s_operand ? svn_fspath__dirname(b->t_path, pool) : b->t_path;
1155
1228
SVN_ERR(check_auth(b, &allowed, t_anchor, pool));
1157
1230
return svn_error_create
1159
1232
_("Not authorized to open root of edit operation"));
1161
1234
/* Collect information about the source and target nodes. */
1162
s_fullpath = svn_path_join(b->fs_base, b->s_operand, pool);
1235
s_fullpath = svn_fspath__join(b->fs_base, b->s_operand, pool);
1163
1236
SVN_ERR(get_source_root(b, &s_root, s_rev));
1164
1237
SVN_ERR(fake_dirent(&s_entry, s_root, s_fullpath, pool));
1165
1238
SVN_ERR(fake_dirent(&t_entry, b->t_root, b->t_path, pool));
1259
1332
svn_error_t *err = drive(b, s_rev, info, pool);
1260
1333
if (err == SVN_NO_ERROR)
1261
return b->editor->close_edit(b->edit_baton, pool);
1262
svn_error_clear(b->editor->abort_edit(b->edit_baton, pool));
1334
return svn_error_trace(b->editor->close_edit(b->edit_baton, pool));
1336
return svn_error_trace(
1337
svn_error_compose_create(err,
1338
b->editor->abort_edit(b->edit_baton,
1279
1355
/* Munge the path to be anchor-relative, so that we can use edit paths
1280
1356
as report paths. */
1281
path = svn_path_join(b->s_operand, path, pool);
1357
path = svn_relpath_join(b->s_operand, path, pool);
1283
1359
lrep = lpath ? apr_psprintf(pool, "+%" APR_SIZE_T_FMT ":%s",
1284
1360
strlen(lpath), lpath) : "-";
1349
1425
finish_err = finish_report(b, pool);
1350
1426
close_err = svn_io_file_close(b->tempfile, pool);
1352
svn_error_clear(close_err);
1353
return finish_err ? finish_err : close_err;
1428
return svn_error_trace(svn_error_compose_create(finish_err, close_err));
1359
1434
report_baton_t *b = baton;
1361
return svn_io_file_close(b->tempfile, pool);
1436
return svn_error_trace(svn_io_file_close(b->tempfile, pool));
1364
1439
/* --- BEGINNING THE REPORT --- */
1391
1466
keep track of them. */
1392
1467
b = apr_palloc(pool, sizeof(*b));
1393
1468
b->repos = repos;
1394
b->fs_base = apr_pstrdup(pool, fs_base);
1469
b->fs_base = svn_fspath__canonicalize(fs_base, pool);
1395
1470
b->s_operand = apr_pstrdup(pool, s_operand);
1396
1471
b->t_rev = revnum;
1397
b->t_path = switch_path ? switch_path
1398
: svn_path_join(fs_base, s_operand, pool);
1472
b->t_path = switch_path ? svn_fspath__canonicalize(switch_path, pool)
1473
: svn_fspath__join(b->fs_base, s_operand, pool);
1399
1474
b->text_deltas = text_deltas;
1400
1475
b->requested_depth = depth;
1401
1476
b->ignore_ancestry = ignore_ancestry;
1405
1480
b->edit_baton = edit_baton;
1406
1481
b->authz_read_func = authz_read_func;
1407
1482
b->authz_read_baton = authz_read_baton;
1483
b->revision_infos = apr_hash_make(pool);
1409
1486
SVN_ERR(svn_io_open_unique_file3(&b->tempfile, NULL, NULL,
1410
1487
svn_io_file_del_on_pool_cleanup,