summaryrefslogtreecommitdiff
path: root/subversion/libsvn_fs_fs/load-index.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_fs_fs/load-index.c')
-rw-r--r--subversion/libsvn_fs_fs/load-index.c98
1 files changed, 87 insertions, 11 deletions
diff --git a/subversion/libsvn_fs_fs/load-index.c b/subversion/libsvn_fs_fs/load-index.c
index 3142e8e354023..0ba66725d35cc 100644
--- a/subversion/libsvn_fs_fs/load-index.c
+++ b/subversion/libsvn_fs_fs/load-index.c
@@ -29,6 +29,53 @@
#include "util.h"
#include "transaction.h"
+/* From the ENTRIES array of svn_fs_fs__p2l_entry_t*, sorted by offset,
+ * return the first offset behind the last item. */
+static apr_off_t
+get_max_covered(apr_array_header_t *entries)
+{
+ const svn_fs_fs__p2l_entry_t *entry;
+ if (entries->nelts == 0)
+ return -1;
+
+ entry = APR_ARRAY_IDX(entries, entries->nelts - 1,
+ const svn_fs_fs__p2l_entry_t *);
+ return entry->offset + entry->size;
+}
+
+/* Make sure that the svn_fs_fs__p2l_entry_t* in ENTRIES are consecutive
+ * and non-overlapping. Use SCRATCH_POOL for temporaries. */
+static svn_error_t *
+check_all_covered(apr_array_header_t *entries,
+ apr_pool_t *scratch_pool)
+{
+ int i;
+ apr_off_t expected = 0;
+ for (i = 0; i < entries->nelts; ++i)
+ {
+ const svn_fs_fs__p2l_entry_t *entry
+ = APR_ARRAY_IDX(entries, i, const svn_fs_fs__p2l_entry_t *);
+
+ if (entry->offset < expected)
+ return svn_error_createf(SVN_ERR_INVALID_INPUT, NULL,
+ "Overlapping index data for offset %s",
+ apr_psprintf(scratch_pool,
+ "%" APR_UINT64_T_HEX_FMT,
+ (apr_uint64_t)expected));
+
+ if (entry->offset > expected)
+ return svn_error_createf(SVN_ERR_INVALID_INPUT, NULL,
+ "Missing index data for offset %s",
+ apr_psprintf(scratch_pool,
+ "%" APR_UINT64_T_HEX_FMT,
+ (apr_uint64_t)expected));
+
+ expected = entry->offset + entry->size;
+ }
+
+ return SVN_NO_ERROR;
+}
+
/* A svn_sort__array compatible comparator function, sorting the
* svn_fs_fs__p2l_entry_t** given in LHS, RHS by offset. */
static int
@@ -52,7 +99,7 @@ svn_fs_fs__load_index(svn_fs_t *fs,
apr_array_header_t *entries,
apr_pool_t *scratch_pool)
{
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_pool_t *subpool = svn_pool_create(scratch_pool);
/* Check the FS format number. */
if (! svn_fs_fs__use_log_addressing(fs))
@@ -68,31 +115,60 @@ svn_fs_fs__load_index(svn_fs_t *fs,
const char *l2p_proto_index;
const char *p2l_proto_index;
svn_fs_fs__revision_file_t *rev_file;
+ svn_error_t *err;
+ apr_off_t max_covered = get_max_covered(entries);
+
+ /* Ensure that the index data is complete. */
+ SVN_ERR(check_all_covered(entries, scratch_pool));
/* Open rev / pack file & trim indexes + footer off it. */
SVN_ERR(svn_fs_fs__open_pack_or_rev_file_writable(&rev_file, fs,
- revision, iterpool,
- iterpool));
- SVN_ERR(svn_fs_fs__auto_read_footer(rev_file));
- SVN_ERR(svn_io_file_trunc(rev_file->file, rev_file->l2p_offset,
- iterpool));
+ revision, subpool,
+ subpool));
+
+ /* Remove the existing index info. */
+ err = svn_fs_fs__auto_read_footer(rev_file);
+ if (err)
+ {
+ /* Even the index footer cannot be read, even less be trusted.
+ * Take the range of valid data from the new index data. */
+ svn_error_clear(err);
+ SVN_ERR(svn_io_file_trunc(rev_file->file, max_covered,
+ subpool));
+ }
+ else
+ {
+ /* We assume that the new index data covers all contents.
+ * Error out if it doesn't. The user can always truncate
+ * the file themselves. */
+ if (max_covered != rev_file->l2p_offset)
+ return svn_error_createf(SVN_ERR_INVALID_INPUT, NULL,
+ "New index data ends at %s, old index ended at %s",
+ apr_psprintf(scratch_pool, "%" APR_UINT64_T_HEX_FMT,
+ (apr_uint64_t)max_covered),
+ apr_psprintf(scratch_pool, "%" APR_UINT64_T_HEX_FMT,
+ (apr_uint64_t) rev_file->l2p_offset));
+
+ SVN_ERR(svn_io_file_trunc(rev_file->file, rev_file->l2p_offset,
+ subpool));
+ }
/* Create proto index files for the new index data
* (will be cleaned up automatically with iterpool). */
SVN_ERR(svn_fs_fs__p2l_index_from_p2l_entries(&p2l_proto_index, fs,
rev_file, entries,
- iterpool, iterpool));
+ subpool, subpool));
SVN_ERR(svn_fs_fs__l2p_index_from_p2l_entries(&l2p_proto_index, fs,
- entries, iterpool,
- iterpool));
+ entries, subpool,
+ subpool));
/* Combine rev data with new index data. */
SVN_ERR(svn_fs_fs__add_index_data(fs, rev_file->file, l2p_proto_index,
p2l_proto_index,
- rev_file->start_revision, iterpool));
+ rev_file->start_revision, subpool));
}
- svn_pool_destroy(iterpool);
+ svn_pool_destroy(subpool);
return SVN_NO_ERROR;
}