Allow cleanup of incomplete component registration.

If ImageLoader crashes, for example due to a seccomp filter violation,
it can leave an incomplete installation on disk that will block a valid
installation from occurring in the future. This makes sure ImageLoader
cleans up any junk left behind from a crash.

BUG=chromium:630421
TEST=emerge-${BOARD} imageloader, setup junk directory, register
component

Change-Id: Ifdc59cd599576c0c40b1bdf98062d4595cf967c0
Reviewed-on: https://chromium-review.googlesource.com/410182
Commit-Ready: Greg Kerr <kerrnel@chromium.org>
Tested-by: Greg Kerr <kerrnel@chromium.org>
Reviewed-by: Ricky Zhou <rickyz@chromium.org>
diff --git a/imageloader_impl.cc b/imageloader_impl.cc
index 0e97131..578d555 100644
--- a/imageloader_impl.cc
+++ b/imageloader_impl.cc
@@ -683,6 +683,13 @@
   // Take ownership of the component and verify it.
   base::FilePath version_path(GetVersionedPath(component_root, version));
   base::FilePath folder_path(component_folder_abs_path);
+
+  // If |version_path| exists but was not the active version, ImageLoader
+  // probably crashed previously and could not cleanup.
+  if (base::PathExists(version_path)) {
+    base::DeleteFile(version_path, /*recursive=*/true);
+  }
+
   if (!CopyComponentDirectory(folder_path, version_path, version)) {
     base::DeleteFile(version_path, /*recursive=*/true);
     return false;
diff --git a/imageloader_unittest.cc b/imageloader_unittest.cc
index 78c1330..6cb9d44 100644
--- a/imageloader_unittest.cc
+++ b/imageloader_unittest.cc
@@ -184,6 +184,28 @@
             loader.GetComponentVersion(kTestComponentName));
 }
 
+// Pretend ImageLoader crashed, by creating an incomplete installation, and then
+// attempt registration with ImageLoader.
+TEST_F(ImageLoaderTest, RegisterComponentAfterCrash) {
+  base::ScopedTempDir scoped_temp_dir;
+  ASSERT_TRUE(scoped_temp_dir.CreateUniqueTempDir());
+  const base::FilePath& temp_dir = scoped_temp_dir.path();
+  // Set the correct permissions on temp dir.
+  ASSERT_TRUE(base::SetPosixFilePermissions(temp_dir, 0755));
+
+  // Now create the junk there.
+  const std::string junk_contents ="Bad file contents";
+  const base::FilePath junk_path =
+      temp_dir.Append(kTestComponentName).Append(kTestDataVersion);
+  ASSERT_TRUE(base::CreateDirectory(junk_path));
+  ASSERT_EQ(static_cast<int>(junk_contents.size()),
+            base::WriteFile(junk_path.Append("junkfile"), junk_contents.data(),
+                            junk_contents.size()));
+  ImageLoaderImpl loader(GetConfig(temp_dir.value().c_str()));
+  ASSERT_TRUE(loader.RegisterComponent(kTestComponentName, kTestDataVersion,
+                                       GetComponentPath().value()));
+}
+
 TEST_F(ImageLoaderTest, ECVerify) {
   ImageLoaderImpl loader(GetConfig("/nonexistant"));
   EXPECT_TRUE(loader.ECVerify(
@@ -268,8 +290,8 @@
   base::FilePath image_path = temp_dir.Append("image");
   std::vector<char> image(image_size,
                           0xBB);  // large enough to test streaming read.
-  ASSERT_TRUE(base::WriteFile(image_path, image.data(), image.size()) ==
-              image_size);
+  ASSERT_EQ(image_size,
+            base::WriteFile(image_path, image.data(), image.size()));
 
   std::vector<uint8_t> hash(crypto::kSHA256Length);