Fix Short read/write issue

It was possible for "short" reads and writes to cause the pattern and
zero steps to not work correctly. This change adds logic to deal with
the short reads.

Tested: unit test and machine test
root@bmc# time busctl call xyz.openbmc_project.eStoraged.mmcblk0 \
> /xyz/openbmc_project/inventory/storage/mmcblk0 \
> xyz.openbmc_project.Inventory.Item.Volume Erase s \
> xyz.openbmc_project.Inventory.Item.Volume.EraseMethod.ZeroOverWrite \
> --timeout=1200
real    6m0.815s
user    0m0.010s
sys     0m0.010s

Change-Id: If8df9bdba159a3bcfa77104a4c17b8d352794db2
Signed-off-by: John Edward Broadbent <jebr@google.com>
diff --git a/include/pattern.hpp b/include/pattern.hpp
index 691cb16..e8c61ee 100644
--- a/include/pattern.hpp
+++ b/include/pattern.hpp
@@ -6,12 +6,13 @@
 #include <stdplus/fd/create.hpp>
 #include <stdplus/fd/managed.hpp>
 
+#include <chrono>
 #include <span>
 #include <string>
 
 namespace estoraged
 {
-using stdplus::fd::ManagedFd;
+using stdplus::fd::Fd;
 
 class Pattern : public Erase
 {
@@ -23,29 +24,48 @@
     Pattern(std::string_view inDevPath) : Erase(inDevPath)
     {}
 
+    /** @brief writes an uncompressible random pattern to the drive, using
+     * default parameters. It also throws errors accordingly.
+     */
+    void writePattern()
+    {
+        stdplus::fd::Fd&& fd =
+            stdplus::fd::open(devPath, stdplus::fd::OpenAccess::WriteOnly);
+        writePattern(util::findSizeOfBlockDevice(devPath), fd);
+    }
+
     /** @brief writes an uncompressible random pattern to the drive
      * and throws errors accordingly.
      *
      *  @param[in] bytes - Size of the block device
+     *  @param[in] fd - the stdplus file descriptor
      */
-    void writePattern()
-    {
-        writePattern(util::findSizeOfBlockDevice(devPath));
-    }
+    void writePattern(uint64_t driveSize, Fd& fd);
 
-    void writePattern(uint64_t driveSize);
+    /** @brief verifies the uncompressible random pattern is on the drive, using
+     * default parameters. It also throws errors accordingly.
+     */
+    void verifyPattern()
+    {
+        stdplus::fd::Fd&& fd =
+            stdplus::fd::open(devPath, stdplus::fd::OpenAccess::ReadOnly);
+        verifyPattern(util::findSizeOfBlockDevice(devPath), fd);
+    }
 
     /** @brief verifies the uncompressible random pattern is on the drive
      * and throws errors accordingly.
      *
      *  @param[in] bytes - Size of the block device
+     *  @param[in] fd - the stdplus file descriptor
      */
+    void verifyPattern(uint64_t driveSize, Fd& fd);
 
-    void verifyPattern()
-    {
-        verifyPattern(util::findSizeOfBlockDevice(devPath));
-    }
-    void verifyPattern(uint64_t driveSize);
+  private:
+    static constexpr uint32_t seed = 0x6a656272;
+    static constexpr size_t blockSize = 4096;
+    static constexpr size_t blockSizeUsing32 = blockSize / sizeof(uint32_t);
+    static constexpr size_t maxRetry = 32;
+    static constexpr std::chrono::duration delay = std::chrono::milliseconds(1);
 };
 
 } // namespace estoraged
diff --git a/include/zero.hpp b/include/zero.hpp
index 562b8ce..bfa240d 100644
--- a/include/zero.hpp
+++ b/include/zero.hpp
@@ -6,10 +6,12 @@
 #include <stdplus/fd/create.hpp>
 #include <stdplus/fd/managed.hpp>
 
+#include <chrono>
+
 namespace estoraged
 {
 
-using stdplus::fd::ManagedFd;
+using stdplus::fd::Fd;
 
 class Zero : public Erase
 {
@@ -23,29 +25,35 @@
     /** @brief writes zero to the drive
      * and throws errors accordingly.
      *  @param[in] driveSize - the size of the block device in bytes
+     *  @param[in] fd - the stdplus file descriptor
      */
-    void writeZero(uint64_t driveSize);
+    void writeZero(uint64_t driveSize, Fd& fd);
 
-    /** @brief writes zero to the drive
+    /** @brief writes zero to the drive using default parameters,
      * and throws errors accordingly.
      */
     void writeZero()
     {
-        writeZero(util::findSizeOfBlockDevice(devPath));
+        stdplus::fd::Fd&& fd =
+            stdplus::fd::open(devPath, stdplus::fd::OpenAccess::WriteOnly);
+        writeZero(util::findSizeOfBlockDevice(devPath), fd);
     }
 
-    /** @brief verifies the  uncompressible random pattern is on the drive
+    /** @brief verifies the drive has only zeros on it,
      * and throws errors accordingly.
      *  @param[in] driveSize - the size of the block device in bytes
+     *  @param[in] fd - the stdplus file descriptor
      */
-    void verifyZero(uint64_t driveSize);
+    void verifyZero(uint64_t driveSize, Fd& fd);
 
-    /** @brief verifies the  uncompressible random pattern is on the drive
-     * and throws errors accordingly.
+    /** @brief verifies the drive has only zeros on it,
+     * using the default parameters. It also throws errors accordingly.
      */
     void verifyZero()
     {
-        verifyZero(util::findSizeOfBlockDevice(devPath));
+        stdplus::fd::Fd&& fd =
+            stdplus::fd::open(devPath, stdplus::fd::OpenAccess::ReadOnly);
+        verifyZero(util::findSizeOfBlockDevice(devPath), fd);
     }
 
   private:
@@ -53,6 +61,8 @@
      * 32768 was also tested. It had almost identical performance.
      */
     static constexpr size_t blockSize = 4096;
+    static constexpr size_t maxRetry = 32;
+    static constexpr std::chrono::duration delay = std::chrono::milliseconds(1);
 };
 
 } // namespace estoraged