test: tmpd: Make VpnorRoot the parent of ro/rw/prsv/patch

Previously it represented any one of the ro/rw/prsv/patch directories.
It's better if we can deal with all of them at once, so rework the
abstraction.

In the process, the patch exploits other features of
std::experimental::filesystem to increase readability of the code.

Change-Id: I06000709622dd66945cc88cb5333847c69215dc7
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
diff --git a/test/vpnor/create_pnor_partition_table.cpp b/test/vpnor/create_pnor_partition_table.cpp
index fb371cb..98d474b 100644
--- a/test/vpnor/create_pnor_partition_table.cpp
+++ b/test/vpnor/create_pnor_partition_table.cpp
@@ -1,12 +1,10 @@
 // SPDX-License-Identifier: Apache-2.0
 // Copyright (C) 2018 IBM Corp.
-#include "pnor_partition_table.hpp"
-#include "config.h"
 #include <assert.h>
 #include <string.h>
-#include <vector>
-#include <fstream>
-#include <experimental/filesystem>
+
+#include "config.h"
+#include "pnor_partition_table.hpp"
 
 #include "test/vpnor/tmpd.hpp"
 
@@ -18,15 +16,14 @@
 };
 constexpr auto partitionName = "HBB";
 
-namespace fs = std::experimental::filesystem;
 namespace test = openpower::virtual_pnor::test;
 
 int main()
 {
     test::VpnorRoot root(toc, BLOCK_SIZE);
 
-    const openpower::virtual_pnor::partition::Table table(
-        fs::path{root.path()}, BLOCK_SIZE, PNOR_SIZE);
+    const openpower::virtual_pnor::partition::Table table(root.ro(), BLOCK_SIZE,
+                                                          PNOR_SIZE);
 
     pnor_partition_table expectedTable{};
     expectedTable.data.magic = PARTITION_HEADER_MAGIC;
diff --git a/test/vpnor/create_read_window_vpnor.cpp b/test/vpnor/create_read_window_vpnor.cpp
index f4c80de..5adb044 100644
--- a/test/vpnor/create_read_window_vpnor.cpp
+++ b/test/vpnor/create_read_window_vpnor.cpp
@@ -71,7 +71,7 @@
     test::VpnorRoot root(toc, BLOCK_SIZE);
     root.write("HBB", data, sizeof(data));
 
-    path = root.path();
+    path = root.ro();
     cpath = path.c_str();
 
     system_set_reserved_size(MEM_SIZE);
diff --git a/test/vpnor/tmpd.cpp b/test/vpnor/tmpd.cpp
index 16a4c2b..6bdfa09 100644
--- a/test/vpnor/tmpd.cpp
+++ b/test/vpnor/tmpd.cpp
@@ -14,16 +14,14 @@
 
 size_t VpnorRoot::write(const std::string &name, const void *data, size_t len)
 {
-    fs::path path{root};
-    path /= name;
+    // write() is for test environment setup - always write to ro section
+    fs::path path = root / "ro" / name;
 
     if (!fs::exists(path))
         /* It's not in the ToC */
         throw std::invalid_argument(name);
 
-    std::ofstream partitionFile(path.c_str());
-    partitionFile.write((const char *)data, len);
-    partitionFile.close();
+    std::ofstream(path).write((const char *)data, len);
 
     return len;
 }
diff --git a/test/vpnor/tmpd.hpp b/test/vpnor/tmpd.hpp
index d684706..28d27c9 100644
--- a/test/vpnor/tmpd.hpp
+++ b/test/vpnor/tmpd.hpp
@@ -29,9 +29,12 @@
         char* tmpdir = mkdtemp(tmplt);
         root = fs::path{tmpdir};
 
-        fs::path tocFilePath{root};
-        tocFilePath /= PARTITION_TOC_FILE;
-        std::ofstream tocFile(tocFilePath.c_str());
+        for (const auto& attr : attributes)
+        {
+            fs::create_directory(root / attr);
+        }
+
+        fs::path tocFilePath = root / "ro" / PARTITION_TOC_FILE;
 
         for (const std::string& line : toc)
         {
@@ -40,19 +43,14 @@
             openpower::virtual_pnor::parseTocLine(line, blockSize, part);
 
             /* Populate the partition in the tree */
-            fs::path partitionFilePath{root};
-            partitionFilePath /= part.data.name;
-            std::ofstream partitionFile(partitionFilePath.c_str());
-            std::vector<char> empty(part.data.size, 0);
-            partitionFile.write(empty.data(), empty.size());
-            partitionFile.close();
+            std::vector<char> zeroed(part.data.actual, 0);
+            fs::path partitionFilePath = root / "ro" / part.data.name;
+            std::ofstream(partitionFilePath)
+                .write(zeroed.data(), zeroed.size());
 
             /* Update the ToC if the partition file was created */
-            tocFile.write(line.c_str(), line.length());
-            tocFile.write("\n", 1);
+            std::ofstream(tocFilePath, std::ofstream::app) << line << "\n";
         }
-
-        tocFile.close();
     }
 
     VpnorRoot(const VpnorRoot&) = delete;
@@ -64,14 +62,27 @@
     {
         fs::remove_all(root);
     }
-    const fs::path& path()
+    fs::path ro()
     {
-        return root;
+        return fs::path{root} / "ro";
+    }
+    fs::path rw()
+    {
+        return fs::path{root} / "rw";
+    }
+    fs::path prsv()
+    {
+        return fs::path{root} / "prsv";
+    }
+    fs::path patch()
+    {
+        return fs::path{root} / "patch";
     }
     size_t write(const std::string& name, const void* data, size_t len);
 
   private:
     fs::path root;
+    const std::string attributes[4] = {"ro", "rw", "prsv", "patch"};
 };
 
 } // test