version-handler: add version-handler, blob handler

Implement version-handler: a blob handler for retrieving version
information about a blob.

Problem: ipmi-flash(firmware-handler) provides a mechanism to transfer
firmware updates, verify them and perform updates but there is no
mechanism to interrogate the firmware for its version.

Solution: version-handler provides handlers for retrieving information
about firmware blobs. Adding "version" syntax to "/flash/blob" entries
in the json configuration file enables this feature.
The mechanism to retrieve version is identical to the mechanism used by
firmware-handler to perform preparation, verification and updates (kick
off systemd targets).

Signed-off-by: Jason Ling <jasonling@google.com>
Change-Id: I28868ca8dd76d63af668d2e46b9359401d45f0bc
diff --git a/bmc/version-handler/version_handler.hpp b/bmc/version-handler/version_handler.hpp
index aefd3c4..336a869 100644
--- a/bmc/version-handler/version_handler.hpp
+++ b/bmc/version-handler/version_handler.hpp
@@ -1,10 +1,18 @@
 #pragma once
 #include "buildjson.hpp"
+#include "image_handler.hpp"
 #include "status.hpp"
+#include "util.hpp"
 
 #include <blobs-ipmid/blobs.hpp>
 
+#include <algorithm>
+#include <cstdint>
+#include <map>
 #include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
 namespace ipmi_flash
 {
 struct VersionActionPack
@@ -16,4 +24,95 @@
     /** Only file operation action supported currently */
     std::unique_ptr<TriggerableActionInterface> onOpen;
 };
+
+/*
+ * All the information associated with a version blob
+ */
+struct VersionInfoPack
+{
+  public:
+    VersionInfoPack(const std::string& blobId,
+                    std::unique_ptr<VersionActionPack> actionPackIn,
+                    std::unique_ptr<ImageHandlerInterface> imageHandler) :
+        blobId(blobId),
+        actionPack(std::move(actionPackIn)),
+        imageHandler(std::move(imageHandler)),
+        blobState(static_cast<blobs::StateFlags>(0)){};
+    VersionInfoPack() = default;
+
+    std::string blobId;
+    std::unique_ptr<VersionActionPack> actionPack;
+    std::unique_ptr<ImageHandlerInterface> imageHandler;
+    blobs::StateFlags blobState;
+};
+
+/* convenience alias: the key (std::string) is blobId, same as
+ * VersionInfoPack.blobId */
+using VersionInfoMap = std::unordered_map<std::string, VersionInfoPack>;
+
+class VersionBlobHandler : public blobs::GenericBlobInterface
+{
+  public:
+    /**
+     * Factory to create a BlobHandler for use by phosphor-ipmi-blobs
+     *
+     * @param[in] versionMap - blob names to VersionInfoPack which contains
+     * triggers, file handlers, state and blobID.
+     *
+     * @returns a unique_ptr to a GenericBlobInterface which is used by
+     * phosphor-ipmi-blobs. The underlying implementation (VersionBlobHandler)
+     * implements all the blob operations for the blobs owned by
+     * VersionBlobHandler.
+     */
+    static std::unique_ptr<blobs::GenericBlobInterface>
+        create(VersionInfoMap&& versionMap);
+    /**
+     * Create a VersionBlobHandler.
+     *
+     * @param[in] blobs - list of blobs_ids to support
+     * @param[in] actions - a map of blobId to VersionInfoPack
+     */
+    VersionBlobHandler(std::vector<std::string>&& blobs,
+                       VersionInfoMap&& handlerMap) :
+        blobIds(blobs),
+        versionInfoMap(std::move(handlerMap))
+    {}
+    ~VersionBlobHandler() = default;
+    VersionBlobHandler(const VersionBlobHandler&) = delete;
+    VersionBlobHandler& operator=(const VersionBlobHandler&) = delete;
+    VersionBlobHandler(VersionBlobHandler&&) = default;
+    VersionBlobHandler& operator=(VersionBlobHandler&&) = default;
+
+    bool canHandleBlob(const std::string& path) override;
+    std::vector<std::string> getBlobIds() override;
+    bool deleteBlob(const std::string& path) override;
+    bool stat(const std::string&, blobs::BlobMeta* meta) override;
+    bool open(uint16_t session, uint16_t flags,
+              const std::string& path) override;
+    std::vector<uint8_t> read(uint16_t session, uint32_t offset,
+                              uint32_t requestedSize) override;
+    bool write(uint16_t session, uint32_t offset,
+               const std::vector<uint8_t>& data) override
+    {
+        return false; /* not supported */
+    };
+    bool writeMeta(uint16_t session, uint32_t offset,
+                   const std::vector<uint8_t>& data) override
+    {
+        return false; /* not supported */
+    }
+    bool commit(uint16_t session, const std::vector<uint8_t>& data) override
+    {
+        return false; // not supported
+    }
+    bool close(uint16_t session) override;
+    bool stat(uint16_t session, blobs::BlobMeta* meta) override;
+    bool expire(uint16_t session) override;
+    bool cleanup(uint16_t session);
+
+  private:
+    std::vector<std::string> blobIds;
+    VersionInfoMap versionInfoMap;
+    std::unordered_map<uint16_t, std::string> sessionToBlob;
+};
 } // namespace ipmi_flash