blob: 75ba9401037e477f10952059cb5dfb95656b34c3 [file] [log] [blame]
#include "version_handler.hpp"
#include <stdexcept>
namespace ipmi_flash
{
std::unique_ptr<blobs::GenericBlobInterface>
VersionBlobHandler::create(VersionInfoMap&& versionMap)
{
if (versionMap.empty())
{
return nullptr;
}
std::vector<std::string> blobList;
for (const auto& [key, val] : versionMap)
{
if (val.blobId != key || val.actionPack == nullptr ||
val.imageHandler == nullptr || val.actionPack->onOpen == nullptr)
{
return nullptr;
}
blobList.push_back(key);
}
return std::make_unique<VersionBlobHandler>(std::move(blobList),
std::move(versionMap));
}
bool VersionBlobHandler::canHandleBlob(const std::string& path)
{
return (std::find(blobIds.begin(), blobIds.end(), path) != blobIds.end());
}
std::vector<std::string> VersionBlobHandler::getBlobIds()
{
return blobIds;
}
/**
* deleteBlob - does nothing, always fails
*/
bool VersionBlobHandler::deleteBlob(const std::string& path)
{
return false;
}
bool VersionBlobHandler::stat(const std::string& path, blobs::BlobMeta* meta)
{
// TODO: stat should return the blob state and in the meta data information
// on whether a read is successful should be contained
// do things like determine if systemd target is triggered
// then check if file can be opened for read
return false; /* not yet implemented */
}
bool VersionBlobHandler::open(uint16_t session, uint16_t flags,
const std::string& path)
{
if (sessionToBlob.insert({session, path}).second == false)
{
fprintf(stderr, "open %s fail: session number %d assigned to %s\n",
path.c_str(), session, sessionToBlob.at(session).c_str());
return false;
}
/* only reads are supported, check if blob is handled and make sure
* the blob isn't already opened
*/
if (flags != blobs::read)
{
fprintf(stderr, "open %s fail: unsupported flags(0x%04X.)\n",
path.c_str(), flags);
cleanup(session);
return false;
}
if (!canHandleBlob(path))
{
fprintf(stderr, "open %s fail: unrecognized blob\n", path.c_str());
cleanup(session);
return false;
}
try
{
auto& v = versionInfoMap.at(path);
if (v.blobState == blobs::StateFlags::open_read)
{
cleanup(session);
fprintf(stderr, "open %s fail: blob already opened for read\n",
path.c_str());
return false;
}
if (v.actionPack->onOpen->trigger() == false)
{
fprintf(stderr, "open %s fail: onOpen trigger failed\n",
path.c_str());
cleanup(session);
return false;
}
v.blobState = blobs::StateFlags::open_read;
return true;
}
catch (const std::out_of_range& e)
{
fprintf(stderr, "open %s fail, exception:%s\n", path.c_str(), e.what());
cleanup(session);
return false;
}
}
std::vector<uint8_t> VersionBlobHandler::read(uint16_t session, uint32_t offset,
uint32_t requestedSize)
{
std::string* blobName;
VersionInfoPack* pack;
try
{
blobName = &sessionToBlob.at(session);
pack = &versionInfoMap.at(*blobName);
}
catch (const std::out_of_range& e)
{
return {};
}
/* onOpen trigger must be successful, otherwise potential
* for stale data to be read
*/
if (pack->actionPack->onOpen->status() != ActionStatus::success)
{
fprintf(stderr, "read failed: onOpen trigger not successful\n");
return {};
}
if (!pack->imageHandler->open("don't care", std::ios::in))
{
fprintf(stderr, "read failed: file open unsuccessful blob=%s\n",
blobName->c_str());
return {};
}
auto d = pack->imageHandler->read(offset, requestedSize);
if (!d)
{
fprintf(stderr, "read failed: unable to read file for blob %s\n",
blobName->c_str());
pack->imageHandler->close();
return {};
}
pack->imageHandler->close();
return *d;
}
bool VersionBlobHandler::close(uint16_t session)
{
return cleanup(session);
}
bool VersionBlobHandler::stat(uint16_t session, blobs::BlobMeta* meta)
{
return false;
}
bool VersionBlobHandler::expire(uint16_t session)
{
return cleanup(session);
}
bool VersionBlobHandler::cleanup(uint16_t session)
{
try
{
const auto& blobName = sessionToBlob.at(session);
auto& pack = versionInfoMap.at(blobName);
if (pack.actionPack->onOpen->status() == ActionStatus::running)
{
pack.actionPack->onOpen->abort();
}
pack.blobState = static_cast<blobs::StateFlags>(0);
sessionToBlob.erase(session);
return true;
}
catch (const std::out_of_range& e)
{
return false;
}
}
} // namespace ipmi_flash