~ubuntu-branches/ubuntu/trusty/subversion/trusty-proposed

« back to all changes in this revision

Viewing changes to subversion/libsvn_repos/reporter.c

  • Committer: Package Import Robot
  • Author(s): Andy Whitcroft
  • Date: 2012-06-21 15:36:36 UTC
  • mfrom: (0.4.13 sid)
  • Revision ID: package-import@ubuntu.com-20120621153636-amqqmuidgwgxz1ly
Tags: 1.7.5-1ubuntu1
* Merge from Debian unstable.  Remaining changes:
  - Create pot file on build.
  - Build a python-subversion-dbg package.
  - Build-depend on python-dbg.
  - Build-depend on default-jre-headless/-jdk.
  - Do not apply java-build patch.
  - debian/rules: Manually create the doxygen output directory, otherwise
    we get weird build failures when running parallel builds.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * reporter.c : `reporter' vtable routines for updates.
3
3
 *
4
4
 * ====================================================================
5
 
 * Copyright (c) 2000-2006, 2008 CollabNet.  All rights reserved.
6
 
 *
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.
12
 
 *
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
 
12
 *
 
13
 *      http://www.apache.org/licenses/LICENSE-2.0
 
14
 *
 
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
 
20
 *    under the License.
16
21
 * ====================================================================
17
22
 */
18
23
 
 
24
#include "svn_dirent_uri.h"
19
25
#include "svn_path.h"
20
26
#include "svn_types.h"
21
27
#include "svn_error.h"
26
32
#include "svn_props.h"
27
33
#include "repos.h"
28
34
#include "svn_private_config.h"
 
35
#include "private/svn_dep_compat.h"
 
36
#include "private/svn_fspath.h"
29
37
 
30
38
#define NUM_CACHED_SOURCE_ROOTS 4
31
39
 
77
85
  apr_pool_t *pool;            /* Container pool */
78
86
} path_info_t;
79
87
 
 
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
 
91
   report generation. */
 
92
typedef struct revision_info_t
 
93
{
 
94
  svn_revnum_t rev;            /* revision number */
 
95
  svn_string_t* date;          /* revision timestamp */
 
96
  svn_string_t* author;        /* name of the revisions' author */
 
97
} revision_info_t;
 
98
 
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
83
102
{
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 */
111
130
  path_info_t *lookahead;
112
131
  svn_fs_root_t *t_root;
113
132
  svn_fs_root_t *s_roots[NUM_CACHED_SOURCE_ROOTS];
 
133
 
 
134
  /* Cache for revision properties. This is used to eliminate redundant
 
135
     revprop fetching. */
 
136
  apr_hash_t* revision_infos;
 
137
 
114
138
  apr_pool_t *pool;
115
139
} report_baton_t;
116
140
 
153
177
read_string(const char **str, apr_file_t *temp, apr_pool_t *pool)
154
178
{
155
179
  apr_uint64_t len;
 
180
  apr_size_t size;
156
181
  char *buf;
157
182
 
158
183
  SVN_ERR(read_number(&len, temp, pool));
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. */
164
 
  if (len + 1 < len)
 
189
  if (len + 1 < len || len + 1 > APR_SIZE_MAX)
165
190
    {
166
191
      /* xgettext doesn't expand preprocessor definitions, so we must
167
192
         pass translatable string to apr_psprintf() function to create
174
199
                               len);
175
200
    }
176
201
 
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));
179
205
  buf[len] = 0;
180
206
  *str = buf;
181
207
  return SVN_NO_ERROR;
419
445
  return b->editor->change_file_prop(file_baton, name, value, pool);
420
446
}
421
447
 
 
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. */
 
451
static  svn_error_t *
 
452
get_revision_info(report_baton_t *b,
 
453
                  svn_revnum_t rev,
 
454
                  revision_info_t** revision_info,
 
455
                  apr_pool_t *scratch_pool)
 
456
{
 
457
  apr_hash_t *r_props;
 
458
  svn_string_t *cdate, *author;
 
459
  revision_info_t* info;
 
460
 
 
461
  /* Try to find the info in the report's cache */
 
462
  info = apr_hash_get(b->revision_infos, &rev, sizeof(rev));
 
463
  if (!info)
 
464
    {
 
465
      /* Info is not available, yet.
 
466
         Get all revprops. */
 
467
      SVN_ERR(svn_fs_revision_proplist(&r_props,
 
468
                                       b->repos->fs,
 
469
                                       rev,
 
470
                                       scratch_pool));
 
471
 
 
472
      /* Extract the committed-date. */
 
473
      cdate = apr_hash_get(r_props, SVN_PROP_REVISION_DATE,
 
474
                           APR_HASH_KEY_STRING);
 
475
 
 
476
      /* Extract the last-author. */
 
477
      author = apr_hash_get(r_props, SVN_PROP_REVISION_AUTHOR,
 
478
                            APR_HASH_KEY_STRING);
 
479
 
 
480
      /* Create a result object */
 
481
      info = apr_palloc(b->pool, sizeof(*info));
 
482
      info->rev = rev;
 
483
      info->date = cdate ? svn_string_dup(cdate, b->pool) : NULL;
 
484
      info->author = author ? svn_string_dup(author, b->pool) : NULL;
 
485
 
 
486
      /* Cache it */
 
487
      apr_hash_set(b->revision_infos, &info->rev, sizeof(rev), info);
 
488
    }
 
489
 
 
490
  *revision_info = info;
 
491
  return SVN_NO_ERROR;
 
492
}
 
493
 
 
494
 
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)
432
505
{
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;
436
509
  int i;
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));
452
526
 
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));
454
528
 
455
529
      /* Transmit the committed-date. */
456
 
      cdate = apr_hash_get(r_props, SVN_PROP_REVISION_DATE,
457
 
                           APR_HASH_KEY_STRING);
458
 
      if (cdate || s_path)
 
530
      if (revision_info->date || s_path)
459
531
        SVN_ERR(change_fn(b, object, SVN_PROP_ENTRY_COMMITTED_DATE,
460
 
                          cdate, pool));
 
532
                          revision_info->date, pool));
461
533
 
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,
467
 
                          last_author, pool));
 
537
                          revision_info->author, pool));
468
538
 
469
539
      /* Transmit the UUID. */
470
540
      SVN_ERR(svn_fs_get_uuid(b->repos->fs, &uuid, pool));
599
669
  else
600
670
    {
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
 
673
             formats */
 
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;
605
678
      *entry = ent;
668
741
         starting with '/', so make sure o_path always starts with a '/'
669
742
         too. */
670
743
      if (*o_path != '/')
671
 
        o_path = apr_pstrcat(pool, "/", o_path, NULL);
 
744
        o_path = apr_pstrcat(pool, "/", o_path, (char *)NULL);
672
745
 
673
746
      SVN_ERR(svn_fs_closest_copy(&closest_copy_root, &closest_copy_path,
674
747
                                  b->t_root, o_path, pool));
748
821
  void *new_baton;
749
822
  svn_checksum_t *checksum;
750
823
  const char *hex_digest;
751
 
  int distance;
752
824
 
753
825
  /* For non-switch operations, follow link_path in the target. */
754
826
  if (info && info->link_path && !b->is_switch)
786
858
  related = FALSE;
787
859
  if (s_entry && t_entry && s_entry->kind == t_entry->kind)
788
860
    {
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))
792
864
        {
806
878
            }
807
879
        }
808
880
 
809
 
      if (distance != -1 || b->ignore_ancestry)
810
 
        related = TRUE;
 
881
      related = (distance != -1 || b->ignore_ancestry);
811
882
    }
812
883
 
813
884
  /* If there's a source and it's not related to the target, nuke it. */
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;
960
 
  void *val;
961
1030
  const char *name, *s_fullpath, *t_fullpath, *e_fullpath;
962
1031
  path_info_t *info;
963
1032
 
984
1053
 
985
1054
      while (1)
986
1055
        {
 
1056
          const svn_fs_dirent_t *s_entry, *t_entry;
 
1057
 
987
1058
          svn_pool_clear(subpool);
988
1059
          SVN_ERR(fetch_path_info(b, &name, &info, e_path, subpool));
989
1060
          if (!name)
1005
1076
              continue;
1006
1077
            }
1007
1078
 
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;
1014
1085
 
1052
1123
               hi;
1053
1124
               hi = apr_hash_next(hi))
1054
1125
            {
 
1126
              const svn_fs_dirent_t *s_entry;
 
1127
 
1055
1128
              svn_pool_clear(subpool);
1056
 
              apr_hash_this(hi, NULL, NULL, &val);
1057
 
              s_entry = val;
 
1129
              s_entry = svn__apr_hash_index_val(hi);
1058
1130
 
1059
1131
              if (apr_hash_get(t_entries, s_entry->name,
1060
1132
                               APR_HASH_KEY_STRING) == NULL)
1071
1143
                    continue;
1072
1144
 
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,
1077
 
                                                              s_entry->name,
1078
 
                                                              subpool),
 
1148
                                                svn_fspath__join(t_path,
 
1149
                                                                 s_entry->name,
 
1150
                                                                 subpool),
1079
1151
                                                s_rev, b->t_rev,
1080
1152
                                                &deleted_rev, subpool));
1081
1153
 
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))
1091
1163
        {
 
1164
          const svn_fs_dirent_t *s_entry, *t_entry;
 
1165
 
1092
1166
          svn_pool_clear(subpool);
1093
 
          apr_hash_this(hi, NULL, NULL, &val);
1094
 
          t_entry = val;
 
1167
          t_entry = svn__apr_hash_index_val(hi);
1095
1168
 
1096
1169
          if (is_depth_upgrade(wc_depth, requested_depth, t_entry->kind))
1097
1170
            {
1118
1191
                  apr_hash_get(s_entries, t_entry->name, APR_HASH_KEY_STRING)
1119
1192
                  : NULL;
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;
1122
1195
            }
1123
1196
 
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);
1127
1200
 
1128
1201
          SVN_ERR(update_entry(b, s_rev, s_fullpath, s_entry, t_fullpath,
1129
1202
                               t_entry, dir_baton, e_fullpath, NULL,
1151
1224
 
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));
1156
1229
  if (!allowed)
1157
1230
    return svn_error_create
1159
1232
       _("Not authorized to open root of edit operation"));
1160
1233
 
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));
1258
1331
  {
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));
1263
 
    return err;
 
1334
      return svn_error_trace(b->editor->close_edit(b->edit_baton, pool));
 
1335
 
 
1336
    return svn_error_trace(
 
1337
                svn_error_compose_create(err,
 
1338
                                         b->editor->abort_edit(b->edit_baton,
 
1339
                                                               pool)));
1264
1340
  }
1265
1341
}
1266
1342
 
1278
1354
 
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);
1282
1358
 
1283
1359
  lrep = lpath ? apr_psprintf(pool, "+%" APR_SIZE_T_FMT ":%s",
1284
1360
                              strlen(lpath), lpath) : "-";
1348
1424
 
1349
1425
  finish_err = finish_report(b, pool);
1350
1426
  close_err = svn_io_file_close(b->tempfile, pool);
1351
 
  if (finish_err)
1352
 
    svn_error_clear(close_err);
1353
 
  return finish_err ? finish_err : close_err;
 
1427
 
 
1428
  return svn_error_trace(svn_error_compose_create(finish_err, close_err));
1354
1429
}
1355
1430
 
1356
1431
svn_error_t *
1358
1433
{
1359
1434
  report_baton_t *b = baton;
1360
1435
 
1361
 
  return svn_io_file_close(b->tempfile, pool);
 
1436
  return svn_error_trace(svn_io_file_close(b->tempfile, pool));
1362
1437
}
1363
1438
 
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);
 
1484
  b->pool = pool;
1408
1485
 
1409
1486
  SVN_ERR(svn_io_open_unique_file3(&b->tempfile, NULL, NULL,
1410
1487
                                   svn_io_file_del_on_pool_cleanup,