Use O_TRUNC + fd->Truncate() instead of dd

Originally CreateBlankImage was used for simple/small partition images
which needed to be reliably zeroed, so performance didn't really matter.
Now we will be using this utility function for larger, multi-GB
partitions, so let's make this code more efficient.

By opening the file with O_CREAT | O_TRUNC we can be sure that even
existing files will be truncated to zero length, and then using
fd->Truncate() they will be implicitly zeroed to the desired size. This
is more efficient as most filesystems don't need to write data blocks
for freelists.

Bug: 156286088
Change-Id: Ief47f2a085222a2f6a9c95b97a06ec2521e6e6f4
Merged-In: Ief47f2a085222a2f6a9c95b97a06ec2521e6e6f4
diff --git a/host/commands/assemble_cvd/data_image.cc b/host/commands/assemble_cvd/data_image.cc
index 701eb67..a19d7dc 100644
--- a/host/commands/assemble_cvd/data_image.cc
+++ b/host/commands/assemble_cvd/data_image.cc
@@ -63,20 +63,24 @@
 } // namespace
 
 void CreateBlankImage(
-    const std::string& image, int block_count, const std::string& image_fmt,
-    const std::string& block_size) {
+    const std::string& image, int num_mb, const std::string& image_fmt) {
   LOG(INFO) << "Creating " << image;
-  std::string of = "of=";
-  of += image;
-  std::string count = "count=";
-  count += std::to_string(block_count);
-  std::string bs = "bs=" + block_size;
-  cvd::execute({"/bin/dd", "if=/dev/zero", of, bs, count});
+  off_t image_size_bytes = static_cast<off_t>(num_mb) << 20;
+  auto fd = cvd::SharedFD::Open(image, O_CREAT | O_TRUNC | O_RDWR, 0666);
+  if (fd->Truncate(image_size_bytes) != 0) {
+    LOG(ERROR) << "`truncate --size=" << num_mb << "M " << image
+               << "` failed:" << fd->StrError();
+    return;
+  }
+  fd->Close();
   if (image_fmt == "ext4") {
     cvd::execute({"/sbin/mkfs.ext4", image});
-  } else if (image_fmt != "none") {
+  } else if (image_fmt == "f2fs") {
     auto make_f2fs_path = vsoc::DefaultHostArtifactsPath("bin/make_f2fs");
     cvd::execute({make_f2fs_path, "-t", image_fmt, image, "-g", "android"});
+  } else if (image_fmt != "none") {
+    LOG(WARNING) << "Unknown image format '" << image_fmt
+                 << "' for " << image << ", treating as 'none'.";
   }
 }
 
diff --git a/host/commands/assemble_cvd/data_image.h b/host/commands/assemble_cvd/data_image.h
index 9d29141..4c4022f 100644
--- a/host/commands/assemble_cvd/data_image.h
+++ b/host/commands/assemble_cvd/data_image.h
@@ -8,5 +8,4 @@
                           const std::string& path);
 bool InitializeMiscImage(const std::string& misc_image);
 void CreateBlankImage(
-    const std::string& image, int block_count, const std::string& image_fmt,
-    const std::string& block_size = "1M");
+    const std::string& image, int num_mb, const std::string& image_fmt);
diff --git a/host/commands/assemble_cvd/flags.cc b/host/commands/assemble_cvd/flags.cc
index b67c360..ee5543a 100644
--- a/host/commands/assemble_cvd/flags.cc
+++ b/host/commands/assemble_cvd/flags.cc
@@ -871,7 +871,7 @@
 
   for (const auto& instance : config->Instances()) {
     if (!cvd::FileExists(instance.access_kregistry_path())) {
-      CreateBlankImage(instance.access_kregistry_path(), 2, "none", "1M");
+      CreateBlankImage(instance.access_kregistry_path(), 2 /* mb */, "none");
     }
   }
 
@@ -897,7 +897,7 @@
                      << "newer than its underlying composite disk. Wiping the overlay.";
       }
       CreateQcowOverlay(config->crosvm_binary(), config->composite_disk_path(), overlay_path);
-      CreateBlankImage(instance.access_kregistry_path(), 2, "none", "1M");
+      CreateBlankImage(instance.access_kregistry_path(), 2 /* mb */, "none");
     }
   }