blob: 6cb836881918733680ec5470c39e8fc3cfa4f879 [file] [log] [blame]
#include "version_handler.hpp"
#include <stdexcept>
#include <utility>
#include <vector>
namespace ipmi_flash
{
VersionBlobHandler::VersionBlobHandler(
std::vector<HandlerConfig<ActionPack>>&& configs)
{
for (auto& config : configs)
{
BlobInfo info = {std::move(config.blobId), std::move(config.actions),
std::move(config.handler)};
if (!blobInfoMap.try_emplace(info.blobId, std::move(info)).second)
{
fprintf(stderr, "Ignoring duplicate config for %s\n",
info.blobId.c_str());
}
}
}
bool VersionBlobHandler::canHandleBlob(const std::string& path)
{
return blobInfoMap.find(path) != blobInfoMap.end();
}
std::vector<std::string> VersionBlobHandler::getBlobIds()
{
std::vector<std::string> ret;
for (const auto& [key, _] : blobInfoMap)
{
ret.push_back(key);
}
return ret;
}
/**
* 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;
}
try
{
auto& v = blobInfoMap.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.actions->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;
BlobInfo* pack;
try
{
blobName = &sessionToBlob.at(session);
pack = &blobInfoMap.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->actions->onOpen->status() != ActionStatus::success)
{
fprintf(stderr, "read failed: onOpen trigger not successful\n");
return {};
}
if (!pack->handler->open("don't care", std::ios::in))
{
fprintf(stderr, "read failed: file open unsuccessful blob=%s\n",
blobName->c_str());
return {};
}
auto d = pack->handler->read(offset, requestedSize);
if (!d)
{
fprintf(stderr, "read failed: unable to read file for blob %s\n",
blobName->c_str());
pack->handler->close();
return {};
}
pack->handler->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 = blobInfoMap.at(blobName);
if (pack.actions->onOpen->status() == ActionStatus::running)
{
pack.actions->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