#include "version_handler.hpp" #include #include #include namespace ipmi_flash { VersionBlobHandler::VersionBlobHandler( std::vector>&& configs) { for (auto& config : configs) { auto info = std::make_unique(); info->blobId = std::move(config.blobId); info->actions = std::move(config.actions); info->handler = 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 VersionBlobHandler::getBlobIds() { std::vector ret; for (const auto& [key, _] : blobInfoMap) { ret.emplace_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) { /* 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); return false; } auto& v = *blobInfoMap.at(path); if (v.blobState == blobs::StateFlags::open_read) { 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()); return false; } v.blobState = blobs::StateFlags::open_read; sessionToBlob[session] = &v; return true; } std::vector VersionBlobHandler::read(uint16_t session, uint32_t offset, uint32_t requestedSize) { BlobInfo* pack; try { pack = sessionToBlob.at(session); } 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", pack->blobId.c_str()); return {}; } auto d = pack->handler->read(offset, requestedSize); if (!d) { fprintf(stderr, "read failed: unable to read file for blob %s\n", pack->blobId.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 { auto& pack = *sessionToBlob.at(session); pack.actions->onOpen->abort(); pack.blobState = static_cast(0); sessionToBlob.erase(session); return true; } catch (const std::out_of_range& e) { return false; } } } // namespace ipmi_flash