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

« back to all changes in this revision

Viewing changes to subversion/libsvn_fs_fs/dag.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:
1
1
/* dag.c : DAG-like interface filesystem, private to libsvn_fs
2
2
 *
3
3
 * ====================================================================
4
 
 * Copyright (c) 2000-2006, 2008 CollabNet.  All rights reserved.
5
 
 *
6
 
 * This software is licensed as described in the file COPYING, which
7
 
 * you should have received as part of this distribution.  The terms
8
 
 * are also available at http://subversion.tigris.org/license-1.html.
9
 
 * If newer versions of this license are posted there, you may use a
10
 
 * newer version instead, at your option.
11
 
 *
12
 
 * This software consists of voluntary contributions made by many
13
 
 * individuals.  For exact contribution history, see the revision
14
 
 * history and logs, available at http://subversion.tigris.org/.
 
4
 *    Licensed to the Apache Software Foundation (ASF) under one
 
5
 *    or more contributor license agreements.  See the NOTICE file
 
6
 *    distributed with this work for additional information
 
7
 *    regarding copyright ownership.  The ASF licenses this file
 
8
 *    to you under the Apache License, Version 2.0 (the
 
9
 *    "License"); you may not use this file except in compliance
 
10
 *    with the License.  You may obtain a copy of the License at
 
11
 *
 
12
 *      http://www.apache.org/licenses/LICENSE-2.0
 
13
 *
 
14
 *    Unless required by applicable law or agreed to in writing,
 
15
 *    software distributed under the License is distributed on an
 
16
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 
17
 *    KIND, either express or implied.  See the License for the
 
18
 *    specific language governing permissions and limitations
 
19
 *    under the License.
15
20
 * ====================================================================
16
21
 */
17
22
 
24
29
#include "svn_pools.h"
25
30
 
26
31
#include "dag.h"
27
 
#include "err.h"
28
32
#include "fs.h"
29
33
#include "key-gen.h"
30
34
#include "fs_fs.h"
32
36
 
33
37
#include "../libsvn_fs/fs-loader.h"
34
38
 
 
39
#include "private/svn_fspath.h"
35
40
#include "svn_private_config.h"
 
41
#include "private/svn_temp_serializer.h"
 
42
#include "temp_serializer.h"
36
43
 
37
44
 
38
45
/* Initializing a filesystem.  */
119
126
  nr->copyfrom_rev = noderev->copyfrom_rev;
120
127
  nr->copyroot_path = apr_pstrdup(pool, noderev->copyroot_path);
121
128
  nr->copyroot_rev = noderev->copyroot_rev;
122
 
  nr->predecessor_count = noderev->predecessor_count;
123
129
  nr->data_rep = svn_fs_fs__rep_copy(noderev->data_rep, pool);
124
130
  nr->prop_rep = svn_fs_fs__rep_copy(noderev->prop_rep, pool);
125
131
  nr->mergeinfo_count = noderev->mergeinfo_count;
131
137
}
132
138
 
133
139
 
134
 
/* Set *NODEREV_P to the cached node-revision for NODE in POOL.
 
140
/* Set *NODEREV_P to the cached node-revision for NODE.
 
141
   If the node-revision was not already cached in NODE, read it in,
 
142
   allocating the cache in POOL.
135
143
 
136
144
   If you plan to change the contents of NODE, be careful!  We're
137
145
   handing you a pointer directly to our cached node-revision, not
303
311
                       const char *name,
304
312
                       apr_pool_t *pool)
305
313
{
306
 
  apr_hash_t *entries;
307
314
  svn_fs_dirent_t *dirent;
308
315
  apr_pool_t *subpool = svn_pool_create(pool);
309
316
 
310
 
  SVN_ERR(svn_fs_fs__dag_dir_entries(&entries, parent, subpool, pool));
311
 
  if (entries)
312
 
    dirent = apr_hash_get(entries, name, APR_HASH_KEY_STRING);
313
 
  else
314
 
    dirent = NULL;
315
 
 
 
317
  SVN_ERR(svn_fs_fs__dag_dir_entry(&dirent, parent, name, subpool, pool));
316
318
  *id_p = dirent ? svn_fs_fs__id_copy(dirent->id, pool) : NULL;
317
319
 
318
320
  svn_pool_destroy(subpool);
351
353
/* Make a new entry named NAME in PARENT.  If IS_DIR is true, then the
352
354
   node revision the new entry points to will be a directory, else it
353
355
   will be a file.  The new node will be allocated in POOL.  PARENT
354
 
   must be mutable, and must not have an entry named NAME.  */
 
356
   must be mutable, and must not have an entry named NAME.
 
357
 
 
358
   Use POOL for all allocations including caching the node_revision in PARENT.
 
359
 */
355
360
static svn_error_t *
356
361
make_entry(dag_node_t **child_p,
357
362
           dag_node_t *parent,
385
390
  /* Create the new node's NODE-REVISION */
386
391
  memset(&new_noderev, 0, sizeof(new_noderev));
387
392
  new_noderev.kind = is_dir ? svn_node_dir : svn_node_file;
388
 
  new_noderev.created_path = svn_path_join(parent_path, name, pool);
 
393
  new_noderev.created_path = svn_fspath__join(parent_path, name, pool);
389
394
 
390
395
  SVN_ERR(get_node_revision(&parent_noderev, parent, pool));
391
396
  new_noderev.copyroot_path = apr_pstrdup(pool,
428
433
  return svn_fs_fs__rep_contents_dir(entries, node->fs, noderev, pool);
429
434
}
430
435
 
 
436
svn_error_t *
 
437
svn_fs_fs__dag_dir_entry(svn_fs_dirent_t **dirent,
 
438
                         dag_node_t *node,
 
439
                         const char* name,
 
440
                         apr_pool_t *pool,
 
441
                         apr_pool_t *node_pool)
 
442
{
 
443
  node_revision_t *noderev;
 
444
  SVN_ERR(get_node_revision(&noderev, node, node_pool));
 
445
 
 
446
  if (noderev->kind != svn_node_dir)
 
447
    return svn_error_create(SVN_ERR_FS_NOT_DIRECTORY, NULL,
 
448
                            _("Can't get entries of non-directory"));
 
449
 
 
450
  /* Get a dirent hash for this directory. */
 
451
  return svn_fs_fs__rep_contents_dir_entry(dirent, node->fs,
 
452
                                           noderev, name, pool);
 
453
}
 
454
 
431
455
 
432
456
svn_error_t *
433
457
svn_fs_fs__dag_set_entry(dag_node_t *node,
678
702
      noderev->predecessor_id = svn_fs_fs__id_copy(cur_entry->id, pool);
679
703
      if (noderev->predecessor_count != -1)
680
704
        noderev->predecessor_count++;
681
 
      noderev->created_path = svn_path_join(parent_path, name, pool);
 
705
      noderev->created_path = svn_fspath__join(parent_path, name, pool);
682
706
 
683
707
      SVN_ERR(svn_fs_fs__create_successor(&new_node_id, fs, cur_entry->id,
684
708
                                          noderev, copy_id, txn_id, pool));
834
858
               hi;
835
859
               hi = apr_hash_next(hi))
836
860
            {
837
 
              void *val;
838
 
              svn_fs_dirent_t *dirent;
 
861
              svn_fs_dirent_t *dirent = svn__apr_hash_index_val(hi);
839
862
 
840
 
              apr_hash_this(hi, NULL, NULL, &val);
841
 
              dirent = val;
842
863
              SVN_ERR(svn_fs_fs__dag_delete_if_mutable(fs, dirent->id,
843
864
                                                       pool));
844
865
            }
1015
1036
      SVN_ERR(svn_fs_fs__dag_file_checksum(&file_checksum, file,
1016
1037
                                           checksum->kind, pool));
1017
1038
      if (!svn_checksum_match(checksum, file_checksum))
1018
 
        return svn_error_createf(SVN_ERR_CHECKSUM_MISMATCH, NULL,
1019
 
                                 _("Checksum mismatch, file '%s':\n"
1020
 
                                   "   expected:  %s\n"
1021
 
                                   "     actual:  %s\n"),
1022
 
                                 file->created_path,
1023
 
                                 svn_checksum_to_cstring_display(checksum,
1024
 
                                                                 pool),
1025
 
                                 svn_checksum_to_cstring_display(file_checksum,
1026
 
                                                                 pool));
 
1039
        return svn_checksum_mismatch_err(checksum, file_checksum, pool,
 
1040
                                         _("Checksum mismatch for '%s'"),
 
1041
                                         file->created_path);
1027
1042
    }
1028
1043
 
1029
1044
  return SVN_NO_ERROR;
1031
1046
 
1032
1047
 
1033
1048
dag_node_t *
1034
 
svn_fs_fs__dag_dup(dag_node_t *node,
 
1049
svn_fs_fs__dag_dup(const dag_node_t *node,
1035
1050
                   apr_pool_t *pool)
1036
1051
{
1037
1052
  /* Allocate our new node. */
1055
1070
}
1056
1071
 
1057
1072
svn_error_t *
1058
 
svn_fs_fs__dag_dup_for_cache(void **out,
1059
 
                             void *in,
1060
 
                             apr_pool_t *pool)
1061
 
{
1062
 
  dag_node_t *in_node = in, *out_node;
1063
 
  out_node = svn_fs_fs__dag_dup(in_node, pool);
1064
 
  out_node->fs = NULL;
1065
 
  *out = out_node;
1066
 
  return SVN_NO_ERROR;
1067
 
}
1068
 
 
1069
 
/* The cache serialization format is:
1070
 
 *
1071
 
 * - For mutable nodes: the character 'M', then 'F' for files or 'D'
1072
 
 *   for directories, then the ID, then '\n', then the created path.
1073
 
 *
1074
 
 * - For immutable nodes: the character 'I' followed by the noderev
1075
 
 *   hash dump (the other fields can be reconstructed from this).  (We
1076
 
 *   assume that, once constructed, immutable nodes always contain
1077
 
 *   their noderev.)
1078
 
 */
1079
 
 
1080
 
svn_error_t *
1081
1073
svn_fs_fs__dag_serialize(char **data,
1082
1074
                         apr_size_t *data_len,
1083
1075
                         void *in,
1084
1076
                         apr_pool_t *pool)
1085
1077
{
1086
1078
  dag_node_t *node = in;
1087
 
  svn_stringbuf_t *buf = svn_stringbuf_create("", pool);
1088
 
 
1089
 
  if (svn_fs_fs__dag_check_mutable(node))
1090
 
    {
1091
 
      svn_stringbuf_appendcstr(buf, "M");
1092
 
      svn_stringbuf_appendcstr(buf, (node->kind == svn_node_file ? "F" : "D"));
1093
 
      svn_stringbuf_appendcstr(buf, svn_fs_fs__id_unparse(node->id,
1094
 
                                                          pool)->data);
1095
 
      svn_stringbuf_appendcstr(buf, "\n");
1096
 
      svn_stringbuf_appendcstr(buf, node->created_path);
1097
 
    }
 
1079
  svn_stringbuf_t *serialized;
 
1080
 
 
1081
  /* create an serialization context and serialize the dag node as root */
 
1082
  svn_temp_serializer__context_t *context =
 
1083
      svn_temp_serializer__init(node,
 
1084
                                sizeof(*node),
 
1085
                                503,
 
1086
                                pool);
 
1087
 
 
1088
  /* for mutable nodes, we will _never_ cache the noderev */
 
1089
  if (node->node_revision && !svn_fs_fs__dag_check_mutable(node))
 
1090
    svn_fs_fs__noderev_serialize(context, &node->node_revision);
1098
1091
  else
1099
 
    {
1100
 
      fs_fs_data_t *ffd = node->fs->fsap_data;
1101
 
      svn_stringbuf_appendcstr(buf, "I");
1102
 
      SVN_ERR(svn_fs_fs__write_noderev(svn_stream_from_stringbuf(buf, pool),
1103
 
                                       node->node_revision, ffd->format,
1104
 
                                       TRUE, pool));
1105
 
    }
1106
 
 
1107
 
  *data = buf->data;
1108
 
  *data_len = buf->len;
 
1092
    svn_temp_serializer__set_null(context,
 
1093
                                  (const void * const *)&node->node_revision);
 
1094
 
 
1095
  /* serialize other sub-structures */
 
1096
  svn_fs_fs__id_serialize(context, (const svn_fs_id_t **)&node->id);
 
1097
  svn_fs_fs__id_serialize(context, &node->fresh_root_predecessor_id);
 
1098
  svn_temp_serializer__add_string(context, &node->created_path);
 
1099
 
 
1100
  /* return serialized data */
 
1101
  serialized = svn_temp_serializer__get(context);
 
1102
  *data = serialized->data;
 
1103
  *data_len = serialized->len;
 
1104
 
1109
1105
  return SVN_NO_ERROR;
1110
1106
}
1111
1107
 
1112
1108
svn_error_t *
1113
1109
svn_fs_fs__dag_deserialize(void **out,
1114
 
                           const char *data,
 
1110
                           char *data,
1115
1111
                           apr_size_t data_len,
1116
1112
                           apr_pool_t *pool)
1117
1113
{
1118
 
  dag_node_t *node = apr_pcalloc(pool, sizeof(*node));
1119
 
 
 
1114
  dag_node_t *node = (dag_node_t *)data;
1120
1115
  if (data_len == 0)
1121
1116
    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
1122
1117
                            _("Empty noderev in cache"));
1123
1118
 
1124
 
  if (*data == 'M')
1125
 
    {
1126
 
      const char *newline;
1127
 
      int id_len;
1128
 
 
1129
 
      data++; data_len--;
1130
 
      if (data_len == 0)
1131
 
        return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
1132
 
                                _("Kindless noderev in cache"));
1133
 
      if (*data == 'F')
1134
 
        node->kind = svn_node_file;
1135
 
      else if (*data == 'D')
1136
 
        node->kind = svn_node_dir;
1137
 
      else
1138
 
        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
1139
 
                                 _("Unknown kind for noderev in cache: '%c'"),
1140
 
                                 *data);
1141
 
 
1142
 
      data++; data_len--;
1143
 
      newline = memchr(data, '\n', data_len);
1144
 
      if (!newline)
1145
 
        return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
1146
 
                                _("Unterminated ID in cache"));
1147
 
      id_len = newline - 1 - data;
1148
 
      node->id = svn_fs_fs__id_parse(data, id_len, pool);
1149
 
      if (! node->id)
1150
 
        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
1151
 
                                 _("Bogus ID '%s' in cache"),
1152
 
                                 apr_pstrndup(pool, data, id_len));
1153
 
 
1154
 
      data += id_len; data_len -= id_len;
1155
 
      data++; data_len--;
1156
 
      if (data_len == 0)
1157
 
        return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
1158
 
                                _("No created path"));
1159
 
      node->created_path = apr_pstrndup(pool, data, data_len);
1160
 
    }
1161
 
  else if (*data == 'I')
1162
 
    {
1163
 
      node_revision_t *noderev;
1164
 
      apr_pool_t *subpool = svn_pool_create(pool);
1165
 
      svn_stream_t *stream =
1166
 
        svn_stream_from_stringbuf(svn_stringbuf_ncreate(data + 1,
1167
 
                                                        data_len - 1,
1168
 
                                                        subpool),
1169
 
                                  subpool);
1170
 
      SVN_ERR(svn_fs_fs__read_noderev(&noderev, stream, pool));
1171
 
      node->kind = noderev->kind;
1172
 
      node->id = svn_fs_fs__id_copy(noderev->id, pool);
1173
 
      node->created_path = apr_pstrdup(pool, noderev->created_path);
1174
 
 
1175
 
      if (noderev->is_fresh_txn_root)
1176
 
        node->fresh_root_predecessor_id = noderev->predecessor_id;
1177
 
 
1178
 
      node->node_revision = noderev;
1179
 
 
1180
 
      svn_pool_destroy(subpool);
1181
 
    }
1182
 
  else
1183
 
    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
1184
 
                             _("Unknown node type in cache: '%c'"), *data);
1185
 
 
 
1119
  /* Copy the _full_ buffer as it also contains the sub-structures. */
 
1120
  node->fs = NULL;
 
1121
 
 
1122
  /* fixup all references to sub-structures */
 
1123
  svn_fs_fs__id_deserialize(node, &node->id);
 
1124
  svn_fs_fs__id_deserialize(node,
 
1125
                            (svn_fs_id_t **)&node->fresh_root_predecessor_id);
 
1126
  svn_fs_fs__noderev_deserialize(node, &node->node_revision);
 
1127
 
 
1128
  svn_temp_deserializer__resolve(node, (void**)&node->created_path);
 
1129
 
 
1130
  /* return result */
1186
1131
  *out = node;
1187
1132
 
1188
1133
  return SVN_NO_ERROR;
1247
1192
      if (to_noderev->predecessor_count != -1)
1248
1193
        to_noderev->predecessor_count++;
1249
1194
      to_noderev->created_path =
1250
 
        svn_path_join(svn_fs_fs__dag_get_created_path(to_node), entry,
1251
 
                      pool);
 
1195
        svn_fspath__join(svn_fs_fs__dag_get_created_path(to_node), entry,
 
1196
                     pool);
1252
1197
      to_noderev->copyfrom_path = apr_pstrdup(pool, from_path);
1253
1198
      to_noderev->copyfrom_rev = from_rev;
1254
1199
 
1313
1258
{
1314
1259
  node_revision_t *noderev;
1315
1260
 
1316
 
  /* Go get a fresh node-revision for FILE. */
 
1261
  /* Go get a fresh node-revision for NODE. */
1317
1262
  SVN_ERR(get_node_revision(&noderev, node, pool));
1318
1263
 
1319
1264
  *rev = noderev->copyroot_rev;
1329
1274
{
1330
1275
  node_revision_t *noderev;
1331
1276
 
1332
 
  /* Go get a fresh node-revision for FILE. */
 
1277
  /* Go get a fresh node-revision for NODE. */
1333
1278
  SVN_ERR(get_node_revision(&noderev, node, pool));
1334
1279
 
1335
1280
  *rev = noderev->copyfrom_rev;
1344
1289
{
1345
1290
  node_revision_t *noderev;
1346
1291
 
1347
 
  /* Go get a fresh node-revision for FILE. */
 
1292
  /* Go get a fresh node-revision for NODE. */
1348
1293
  SVN_ERR(get_node_revision(&noderev, node, pool));
1349
1294
 
1350
1295
  *path = noderev->copyfrom_path;
1351
1296
 
1352
1297
  return SVN_NO_ERROR;
1353
1298
}
 
1299
 
 
1300
svn_error_t *
 
1301
svn_fs_fs__dag_update_ancestry(dag_node_t *target,
 
1302
                               dag_node_t *source,
 
1303
                               apr_pool_t *pool)
 
1304
{
 
1305
  node_revision_t *source_noderev, *target_noderev;
 
1306
 
 
1307
  if (! svn_fs_fs__dag_check_mutable(target))
 
1308
    return svn_error_createf
 
1309
      (SVN_ERR_FS_NOT_MUTABLE, NULL,
 
1310
       _("Attempted to update ancestry of non-mutable node"));
 
1311
 
 
1312
  SVN_ERR(get_node_revision(&source_noderev, source, pool));
 
1313
  SVN_ERR(get_node_revision(&target_noderev, target, pool));
 
1314
 
 
1315
  target_noderev->predecessor_id = source->id;
 
1316
  target_noderev->predecessor_count = source_noderev->predecessor_count;
 
1317
  if (target_noderev->predecessor_count != -1)
 
1318
    target_noderev->predecessor_count++;
 
1319
 
 
1320
  return svn_fs_fs__put_node_revision(target->fs, target->id, target_noderev,
 
1321
                                      FALSE, pool);
 
1322
}