update_engine: Add fds for the source partitions.

Add new fds for the source partition, one for the rootfs and another for
the kernel. These are opened if we have a delta update with minor
version 2.

This change also adds support for changing the minor versions in tests.
There is a new private member, supported_minor_version_, which defaults
to kSupportedMinorPayloadVersion. It is set in the unit tests with calls
to SetSupportedVersion.

BUG=chromium:463573
TEST=`FEATURES=test emerge-link update_engine`

Change-Id: Ib988c91eb450b2499c615ae65b271691dfd9c651
Reviewed-on: https://chromium-review.googlesource.com/260950
Trybot-Ready: Allie Wood <alliewood@chromium.org>
Tested-by: Allie Wood <alliewood@chromium.org>
Reviewed-by: Alex Deymo <deymo@chromium.org>
Commit-Queue: Allie Wood <alliewood@chromium.org>
diff --git a/delta_performer_unittest.cc b/delta_performer_unittest.cc
index 5109fa0..fc2ac7e 100644
--- a/delta_performer_unittest.cc
+++ b/delta_performer_unittest.cc
@@ -107,8 +107,37 @@
   kValidOperationData,
 };
 
+// Chuck size used for full payloads during test.
+size_t kDefaultFullChunkSize = 1024 * 1024;
+
 }  // namespace
 
+class DeltaPerformerTest : public ::testing::Test {
+ public:
+  // Test helper placed where it can easily be friended from DeltaPerformer.
+  static void RunManifestValidation(const DeltaArchiveManifest& manifest,
+                                    bool full_payload,
+                                    ErrorCode expected) {
+    MockPrefs prefs;
+    InstallPlan install_plan;
+    FakeSystemState fake_system_state;
+    DeltaPerformer performer(&prefs, &fake_system_state, &install_plan);
+
+    // The install plan is for Full or Delta.
+    install_plan.is_full_update = full_payload;
+
+    // The Manifest we are validating.
+    performer.manifest_.CopyFrom(manifest);
+
+    EXPECT_EQ(expected, performer.ValidateManifest());
+  }
+
+  static void SetSupportedVersion(DeltaPerformer* performer,
+                                  uint64_t minor_version) {
+    performer->supported_minor_version_ = minor_version;
+  }
+};
+
 static void CompareFilesByBlock(const string& a_file, const string& b_file) {
   chromeos::Blob a_data, b_data;
   EXPECT_TRUE(utils::ReadFile(a_file, &a_data)) << "file failed: " << a_file;
@@ -281,7 +310,8 @@
                               bool noop,
                               off_t chunk_size,
                               SignatureTest signature_test,
-                              DeltaState *state) {
+                              DeltaState *state,
+                              uint32_t minor_version) {
   EXPECT_TRUE(utils::MakeTempFile("a_img.XXXXXX", &state->a_img, nullptr));
   EXPECT_TRUE(utils::MakeTempFile("b_img.XXXXXX", &state->b_img, nullptr));
   test_utils::CreateExtImageAtPath(state->a_img, nullptr);
@@ -474,6 +504,7 @@
     payload_config.is_delta = !full_rootfs;
     payload_config.chunk_size = chunk_size;
     payload_config.rootfs_partition_size = kRootFSPartitionSize;
+    payload_config.minor_version = minor_version;
     if (!full_rootfs) {
       payload_config.source.rootfs_part = state->a_img;
       payload_config.source.rootfs_mountpt = a_mnt;
@@ -482,10 +513,9 @@
       payload_config.source.image_info = old_image_info;
       EXPECT_TRUE(payload_config.source.LoadImageSize());
 
-      payload_config.minor_version =
-          DeltaPerformer::kSupportedMinorPayloadVersion;
     } else {
-      payload_config.minor_version = DeltaPerformer::kFullPayloadMinorVersion;
+      if (payload_config.chunk_size == -1)
+        payload_config.chunk_size = kDefaultFullChunkSize;
     }
     payload_config.target.rootfs_part = state->b_img;
     payload_config.target.rootfs_mountpt = b_mnt;
@@ -538,7 +568,8 @@
                            SignatureTest signature_test, DeltaState* state,
                            bool hash_checks_mandatory,
                            OperationHashTest op_hash_test,
-                           DeltaPerformer** performer) {
+                           DeltaPerformer** performer,
+                           uint32_t minor_version) {
   // Check the metadata.
   {
     DeltaArchiveManifest manifest;
@@ -665,6 +696,8 @@
   install_plan.hash_checks_mandatory = hash_checks_mandatory;
   install_plan.metadata_size = state->metadata_size;
   install_plan.is_full_update = full_kernel && full_rootfs;
+  install_plan.source_path = state->a_img.c_str();
+  install_plan.kernel_source_path = state->old_kernel.c_str();
 
   LOG(INFO) << "Setting payload metadata size in Omaha  = "
             << state->metadata_size;
@@ -680,6 +713,7 @@
                                   &install_plan);
   EXPECT_TRUE(utils::FileExists(kUnittestPublicKeyPath));
   (*performer)->set_public_key_path(kUnittestPublicKeyPath);
+  DeltaPerformerTest::SetSupportedVersion(*performer, minor_version);
 
   EXPECT_EQ(state->image_size,
             OmahaHashCalculator::RawHashOfFile(state->a_img,
@@ -713,6 +747,12 @@
       break;
   }
 
+  // For now, source operations are not implemented, so we expect an error.
+  if (minor_version == kSourceMinorPayloadVersion) {
+    expected_error = ErrorCode::kDownloadOperationExecutionError;
+    continue_writing = false;
+  }
+
   // Write at some number of bytes per operation. Arbitrarily chose 5.
   const size_t kBytesPerWrite = 5;
   for (size_t i = 0; i < state->delta.size(); i += kBytesPerWrite) {
@@ -823,11 +863,11 @@
 void DoSmallImageTest(bool full_kernel, bool full_rootfs, bool noop,
                       off_t chunk_size,
                       SignatureTest signature_test,
-                      bool hash_checks_mandatory) {
+                      bool hash_checks_mandatory, uint32_t minor_version) {
   DeltaState state;
   DeltaPerformer *performer = nullptr;
   GenerateDeltaFile(full_kernel, full_rootfs, noop, chunk_size,
-                    signature_test, &state);
+                    signature_test, &state, minor_version);
 
   ScopedPathUnlinker a_img_unlinker(state.a_img);
   ScopedPathUnlinker b_img_unlinker(state.b_img);
@@ -836,7 +876,7 @@
   ScopedPathUnlinker new_kernel_unlinker(state.new_kernel);
   ApplyDeltaFile(full_kernel, full_rootfs, noop, signature_test,
                  &state, hash_checks_mandatory, kValidOperationData,
-                 &performer);
+                 &performer, minor_version);
   VerifyPayload(performer, &state, signature_test);
   delete performer;
 }
@@ -889,7 +929,8 @@
   // Using kSignatureNone since it doesn't affect the results of our test.
   // If we've to use other signature options, then we'd have to get the
   // metadata size again after adding the signing operation to the manifest.
-  GenerateDeltaFile(true, true, false, -1, signature_test, &state);
+  GenerateDeltaFile(true, true, false, -1, signature_test, &state,
+                    DeltaPerformer::kFullPayloadMinorVersion);
 
   ScopedPathUnlinker a_img_unlinker(state.a_img);
   ScopedPathUnlinker b_img_unlinker(state.b_img);
@@ -972,40 +1013,21 @@
 void DoOperationHashMismatchTest(OperationHashTest op_hash_test,
                                  bool hash_checks_mandatory) {
   DeltaState state;
-  GenerateDeltaFile(true, true, false, -1, kSignatureGenerated, &state);
+  uint64_t minor_version = DeltaPerformer::kFullPayloadMinorVersion;
+  GenerateDeltaFile(true, true, false, -1, kSignatureGenerated, &state,
+                    minor_version);
   ScopedPathUnlinker a_img_unlinker(state.a_img);
   ScopedPathUnlinker b_img_unlinker(state.b_img);
   ScopedPathUnlinker delta_unlinker(state.delta_path);
   ScopedPathUnlinker old_kernel_unlinker(state.old_kernel);
   ScopedPathUnlinker new_kernel_unlinker(state.new_kernel);
   DeltaPerformer *performer = nullptr;
-  ApplyDeltaFile(true, true, false, kSignatureGenerated,
-                 &state, hash_checks_mandatory, op_hash_test, &performer);
+  ApplyDeltaFile(true, true, false, kSignatureGenerated, &state,
+                 hash_checks_mandatory, op_hash_test, &performer,
+                 minor_version);
   delete performer;
 }
 
-
-class DeltaPerformerTest : public ::testing::Test {
- public:
-  // Test helper placed where it can easily be friended from DeltaPerformer.
-  static void RunManifestValidation(const DeltaArchiveManifest& manifest,
-                                    bool full_payload,
-                                    ErrorCode expected) {
-    MockPrefs prefs;
-    InstallPlan install_plan;
-    FakeSystemState fake_system_state;
-    DeltaPerformer performer(&prefs, &fake_system_state, &install_plan);
-
-    // The install plan is for Full or Delta.
-    install_plan.is_full_update = full_payload;
-
-    // The Manifest we are validating.
-    performer.manifest_.CopyFrom(manifest);
-
-    EXPECT_EQ(expected, performer.ValidateManifest());
-  }
-};
-
 TEST(DeltaPerformerTest, ExtentsToByteStringTest) {
   uint64_t test[] = {1, 1, 4, 2, kSparseHole, 1, 0, 1};
   COMPILE_ASSERT(arraysize(test) % 2 == 0, array_size_uneven);
@@ -1110,68 +1132,69 @@
 
 TEST(DeltaPerformerTest, RunAsRootSmallImageTest) {
   DoSmallImageTest(false, false, false, -1, kSignatureGenerator,
-                   false);
+                   false, kInPlaceMinorPayloadVersion);
 }
 
 TEST(DeltaPerformerTest, RunAsRootSmallImageSignaturePlaceholderTest) {
   DoSmallImageTest(false, false, false, -1, kSignatureGeneratedPlaceholder,
-                   false);
+                   false, kInPlaceMinorPayloadVersion);
 }
 
 TEST(DeltaPerformerTest, RunAsRootSmallImageSignaturePlaceholderMismatchTest) {
   DeltaState state;
   GenerateDeltaFile(false, false, false, -1,
-                    kSignatureGeneratedPlaceholderMismatch, &state);
+                    kSignatureGeneratedPlaceholderMismatch, &state,
+                    kInPlaceMinorPayloadVersion);
 }
 
 TEST(DeltaPerformerTest, RunAsRootSmallImageChunksTest) {
   DoSmallImageTest(false, false, false, kBlockSize, kSignatureGenerator,
-                   false);
+                   false, kInPlaceMinorPayloadVersion);
 }
 
 TEST(DeltaPerformerTest, RunAsRootFullKernelSmallImageTest) {
   DoSmallImageTest(true, false, false, -1, kSignatureGenerator,
-                   false);
+                   false, kInPlaceMinorPayloadVersion);
 }
 
 TEST(DeltaPerformerTest, RunAsRootFullSmallImageTest) {
   DoSmallImageTest(true, true, false, -1, kSignatureGenerator,
-                   true);
+                   true, DeltaPerformer::kFullPayloadMinorVersion);
 }
 
 TEST(DeltaPerformerTest, RunAsRootNoopSmallImageTest) {
   DoSmallImageTest(false, false, true, -1, kSignatureGenerator,
-                   false);
+                   false, kInPlaceMinorPayloadVersion);
 }
 
 TEST(DeltaPerformerTest, RunAsRootSmallImageSignNoneTest) {
   DoSmallImageTest(false, false, false, -1, kSignatureNone,
-                   false);
+                   false, kInPlaceMinorPayloadVersion);
 }
 
 TEST(DeltaPerformerTest, RunAsRootSmallImageSignGeneratedTest) {
   DoSmallImageTest(false, false, false, -1, kSignatureGenerated,
-                   true);
+                   true, kInPlaceMinorPayloadVersion);
 }
 
 TEST(DeltaPerformerTest, RunAsRootSmallImageSignGeneratedShellTest) {
   DoSmallImageTest(false, false, false, -1, kSignatureGeneratedShell,
-                   false);
+                   false, kInPlaceMinorPayloadVersion);
 }
 
 TEST(DeltaPerformerTest, RunAsRootSmallImageSignGeneratedShellBadKeyTest) {
   DoSmallImageTest(false, false, false, -1, kSignatureGeneratedShellBadKey,
-                   false);
+                   false, kInPlaceMinorPayloadVersion);
 }
 
 TEST(DeltaPerformerTest, RunAsRootSmallImageSignGeneratedShellRotateCl1Test) {
   DoSmallImageTest(false, false, false, -1, kSignatureGeneratedShellRotateCl1,
-                   false);
+                   false, kInPlaceMinorPayloadVersion);
 }
 
 TEST(DeltaPerformerTest, RunAsRootSmallImageSignGeneratedShellRotateCl2Test) {
   DoSmallImageTest(false, false, false, -1, kSignatureGeneratedShellRotateCl2,
-                   false);
+                   false, kInPlaceMinorPayloadVersion);
 }
 
 TEST(DeltaPerformerTest, BadDeltaMagicTest) {
@@ -1354,6 +1377,24 @@
   EXPECT_TRUE(test_utils::RecursiveUnlinkDir(temp_dir));
 }
 
+TEST(DeltaPerformerTest, RunAsRootSourceOperationsTest) {
+  // Make sure we can generate a payload with the new source ops and minor
+  // version 2. For now, we expect ApplyDeltaFile to fail because the ops are
+  // not yet implemented, but eventually we can verify the resulting payload.
+  DeltaState state;
+  DeltaPerformer* performer = nullptr;
+  GenerateDeltaFile(false, false, false, -1, kSignatureNone, &state,
+                    kSourceMinorPayloadVersion);
+  ScopedPathUnlinker a_img_unlinker(state.a_img);
+  ScopedPathUnlinker b_img_unlinker(state.b_img);
+  ScopedPathUnlinker delta_unlinker(state.delta_path);
+  ScopedPathUnlinker old_kernel_unlinker(state.old_kernel);
+  ScopedPathUnlinker new_kernel_unlinker(state.new_kernel);
+  ApplyDeltaFile(false, false, false, kSignatureNone, &state, false,
+                 kValidOperationData, &performer, kSourceMinorPayloadVersion);
+  delete performer;
+}
+
 TEST(DeltaPerformerTest, MinorVersionsMatch) {
   // Test that the minor version in update_engine.conf that is installed to
   // the image matches the supported delta minor version in the update engine.