You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2015/11/07 15:35:30 UTC

svn commit: r1713132 - /subversion/trunk/subversion/libsvn_fs_x/revprops.c

Author: stefan2
Date: Sat Nov  7 14:35:30 2015
New Revision: 1713132

URL: http://svn.apache.org/viewvc?rev=1713132&view=rev
Log:
Add a checkum to the revprop manifests in FSX and verify it upon read.
So, this check is also implict when 'svnadmin verify' accesses the revprops.

* subversion/libsvn_fs_x/revprops.c
  (write_manifest): Append a 4-byte checksum to the actual manifest.
  (read_manifest): Read and verify the checksum before processing the
                   actual manifest.
  (get_revprop_packname,
   write_packed_revprop,
   svn_fs_x__pack_revprops_shard): Update callers.  The manifest de-/
                                   serialization functions create their
                                   stream objects on demand now.

Modified:
    subversion/trunk/subversion/libsvn_fs_x/revprops.c

Modified: subversion/trunk/subversion/libsvn_fs_x/revprops.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/revprops.c?rev=1713132&r1=1713131&r2=1713132&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/revprops.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/revprops.c Sat Nov  7 14:35:30 2015
@@ -476,15 +476,17 @@ read_non_packed_revprop(apr_hash_t **pro
   return SVN_NO_ERROR;
 }
 
-/* Serialize the packed revprops MANIFEST into STREAM.
+/* Serialize the packed revprops MANIFEST into FILE.
  * Use SCRATCH_POOL for temporary allocations.
  */
 static svn_error_t *
-write_manifest(svn_stream_t *stream,
+write_manifest(apr_file_t *file,
                const apr_array_header_t *manifest,
                apr_pool_t *scratch_pool)
 {
   int i;
+  svn_checksum_t *checksum;
+  svn_stream_t *stream;
   svn_packed__data_root_t *root = svn_packed__data_create_root(scratch_pool);
 
   /* one top-level stream per struct element */
@@ -501,29 +503,65 @@ write_manifest(svn_stream_t *stream,
       svn_packed__add_uint(tag_stream, entry->tag);
     }
 
-  /* write to stream */
+  /* Write to file and calculate the checksum. */
+  stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
+  stream = svn_checksum__wrap_write_stream(&checksum, stream,
+                                           svn_checksum_fnv1a_32x4,
+                                           scratch_pool);
   SVN_ERR(svn_packed__data_write(stream, root, scratch_pool));
+  SVN_ERR(svn_stream_close(stream));
+
+  /* Append the checksum */
+  SVN_ERR(svn_io_file_write_full(file, checksum->digest,
+                                 svn_checksum_size(checksum), NULL,
+                                 scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
-/* Read the packed revprops manifest from STREAM and return it in *MANIFEST,
- * allocated in RESULT_POOL. Use SCRATCH_POOL for temporary allocations.
+/* Read the packed revprops manifest from the CONTENT buffer and return it
+ * in *MANIFEST, allocated in RESULT_POOL.  REVISION is the revision number
+ * to put into error messages.  Use SCRATCH_POOL for temporary allocations.
  */
 static svn_error_t *
 read_manifest(apr_array_header_t **manifest,
-               svn_stream_t *stream,
-               apr_pool_t *result_pool,
-               apr_pool_t *scratch_pool)
+              svn_stringbuf_t *content,
+              svn_revnum_t revision,
+              apr_pool_t *result_pool,
+              apr_pool_t *scratch_pool)
 {
+  apr_size_t data_len;
   apr_size_t i;
   apr_size_t count;
 
+  svn_stream_t *stream;
   svn_packed__data_root_t *root;
   svn_packed__int_stream_t *start_rev_stream;
   svn_packed__int_stream_t *tag_stream;
+  const apr_byte_t *digest;
+  svn_checksum_t *actual, *expected;
 
-  /* read everything from disk */
+  /* Verify the checksum. */
+  if (content->len < sizeof(apr_uint32_t))
+    return svn_error_createf(SVN_ERR_FS_CORRUPT_REVPROP_MANIFEST, NULL,
+                             "Revprop manifest too short for revision r%ld",
+                             revision);
+
+  data_len = content->len - sizeof(apr_uint32_t);
+  digest = (apr_byte_t *)content->data + data_len;
+
+  expected = svn_checksum__from_digest_fnv1a_32x4(digest, scratch_pool);
+  SVN_ERR(svn_checksum(&actual, svn_checksum_fnv1a_32x4, content->data,
+                       data_len, scratch_pool));
+
+  if (!svn_checksum_match(actual, expected))
+    SVN_ERR(svn_checksum_mismatch_err(expected, actual, scratch_pool, 
+                                      _("checksum mismatch in revprop "
+                                        "manifest for revision r%ld"),
+                                      revision));
+
+  /* read everything from the buffer */
+  stream = svn_stream_from_stringbuf(content, scratch_pool);
   SVN_ERR(svn_packed__data_read(&root, stream, result_pool, scratch_pool));
 
   /* get streams */
@@ -606,7 +644,6 @@ get_revprop_packname(svn_fs_t *fs,
   svn_fs_x__data_t *ffd = fs->fsap_data;
   svn_stringbuf_t *content = NULL;
   const char *manifest_file_path;
-  svn_stream_t *stream;
   int idx;
   svn_revnum_t previous_start_rev;
   int i;
@@ -627,10 +664,8 @@ get_revprop_packname(svn_fs_t *fs,
   manifest_file_path = svn_dirent_join(revprops->folder, PATH_MANIFEST,
                                        result_pool);
   SVN_ERR(svn_fs_x__read_content(&content, manifest_file_path, result_pool));
-
-  stream = svn_stream_from_stringbuf(content, scratch_pool);
-  SVN_ERR(read_manifest(&revprops->manifest, stream, result_pool,
-                        scratch_pool));
+  SVN_ERR(read_manifest(&revprops->manifest, content, revprops->revision,
+                        result_pool, scratch_pool));
 
   /* Verify the manifest data. */
   if (revprops->manifest->nelts == 0)
@@ -1377,10 +1412,7 @@ write_packed_revprop(const char **final_
       *tmp_path = apr_pstrcat(result_pool, *final_path, ".tmp", SVN_VA_NULL);
       SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, *tmp_path,
                                               scratch_pool));
-
-      stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
-      SVN_ERR(write_manifest(stream, revprops->manifest, scratch_pool));
-      SVN_ERR(svn_stream_close(stream));
+      SVN_ERR(write_manifest(file, revprops->manifest, scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -1598,7 +1630,6 @@ svn_fs_x__pack_revprops_shard(svn_fs_t *
 {
   const char *manifest_file_path, *pack_filename = NULL;
   apr_file_t *manifest_file;
-  svn_stream_t *manifest_stream;
   svn_revnum_t start_rev, end_rev, rev;
   apr_off_t total_size;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
@@ -1609,11 +1640,9 @@ svn_fs_x__pack_revprops_shard(svn_fs_t *
   manifest_file_path = svn_dirent_join(pack_file_dir, PATH_MANIFEST,
                                        scratch_pool);
 
-  /* Create the manifest file stream. */
+  /* Create the manifest file. */
   SVN_ERR(svn_fs_x__batch_fsync_open_file(&manifest_file, batch,
                                           manifest_file_path, scratch_pool));
-  manifest_stream = svn_stream_from_aprfile2(manifest_file, TRUE,
-                                             scratch_pool);
 
   /* revisions to handle. Special case: revision 0 */
   start_rev = (svn_revnum_t) (shard * max_files_per_dir);
@@ -1692,8 +1721,7 @@ svn_fs_x__pack_revprops_shard(svn_fs_t *
                           (apr_size_t)total_size, compression_level,
                           batch, cancel_func, cancel_baton, iterpool));
 
-  SVN_ERR(write_manifest(manifest_stream, manifest, iterpool));
-  SVN_ERR(svn_stream_close(manifest_stream));
+  SVN_ERR(write_manifest(manifest_file, manifest, iterpool));
 
   /* flush all data to disk and update permissions */
   SVN_ERR(svn_io_copy_perms(shard_path, pack_file_dir, iterpool));