1 #include "version_handler.hpp" 2 3 #include <stdexcept> 4 #include <utility> 5 #include <vector> 6 7 namespace ipmi_flash 8 { 9 10 VersionBlobHandler::VersionBlobHandler( 11 std::vector<HandlerConfig<ActionPack>>&& configs) 12 { 13 for (auto& config : configs) 14 { 15 auto info = std::make_unique<BlobInfo>(); 16 info->blobId = std::move(config.blobId); 17 info->actions = std::move(config.actions); 18 info->handler = std::move(config.handler); 19 if (!blobInfoMap.try_emplace(info->blobId, std::move(info)).second) 20 { 21 fprintf(stderr, "Ignoring duplicate config for %s\n", 22 info->blobId.c_str()); 23 } 24 } 25 } 26 27 bool VersionBlobHandler::canHandleBlob(const std::string& path) 28 { 29 return blobInfoMap.find(path) != blobInfoMap.end(); 30 } 31 32 std::vector<std::string> VersionBlobHandler::getBlobIds() 33 { 34 std::vector<std::string> ret; 35 for (const auto& [key, _] : blobInfoMap) 36 { 37 ret.emplace_back(key); 38 } 39 return ret; 40 } 41 42 /** 43 * deleteBlob - does nothing, always fails 44 */ 45 bool VersionBlobHandler::deleteBlob(const std::string& path) 46 { 47 return false; 48 } 49 50 bool VersionBlobHandler::stat(const std::string& path, blobs::BlobMeta* meta) 51 { 52 // TODO: stat should return the blob state and in the meta data information 53 // on whether a read is successful should be contained 54 // do things like determine if systemd target is triggered 55 // then check if file can be opened for read 56 return false; /* not yet implemented */ 57 } 58 59 bool VersionBlobHandler::open(uint16_t session, uint16_t flags, 60 const std::string& path) 61 { 62 /* only reads are supported, check if blob is handled and make sure 63 * the blob isn't already opened 64 */ 65 if (flags != blobs::read) 66 { 67 fprintf(stderr, "open %s fail: unsupported flags(0x%04X.)\n", 68 path.c_str(), flags); 69 return false; 70 } 71 72 auto& v = *blobInfoMap.at(path); 73 if (v.blobState == blobs::StateFlags::open_read) 74 { 75 fprintf(stderr, "open %s fail: blob already opened for read\n", 76 path.c_str()); 77 return false; 78 } 79 if (v.actions->onOpen->trigger() == false) 80 { 81 fprintf(stderr, "open %s fail: onOpen trigger failed\n", path.c_str()); 82 return false; 83 } 84 85 v.blobState = blobs::StateFlags::open_read; 86 sessionToBlob[session] = &v; 87 return true; 88 } 89 90 std::vector<uint8_t> VersionBlobHandler::read(uint16_t session, uint32_t offset, 91 uint32_t requestedSize) 92 { 93 BlobInfo* pack; 94 try 95 { 96 pack = sessionToBlob.at(session); 97 } 98 catch (const std::out_of_range& e) 99 { 100 return {}; 101 } 102 /* onOpen trigger must be successful, otherwise potential 103 * for stale data to be read 104 */ 105 if (pack->actions->onOpen->status() != ActionStatus::success) 106 { 107 fprintf(stderr, "read failed: onOpen trigger not successful\n"); 108 return {}; 109 } 110 if (!pack->handler->open("don't care", std::ios::in)) 111 { 112 fprintf(stderr, "read failed: file open unsuccessful blob=%s\n", 113 pack->blobId.c_str()); 114 return {}; 115 } 116 auto d = pack->handler->read(offset, requestedSize); 117 if (!d) 118 { 119 fprintf(stderr, "read failed: unable to read file for blob %s\n", 120 pack->blobId.c_str()); 121 pack->handler->close(); 122 return {}; 123 } 124 pack->handler->close(); 125 return *d; 126 } 127 128 bool VersionBlobHandler::close(uint16_t session) 129 { 130 return cleanup(session); 131 } 132 133 bool VersionBlobHandler::stat(uint16_t session, blobs::BlobMeta* meta) 134 { 135 return false; 136 } 137 138 bool VersionBlobHandler::expire(uint16_t session) 139 { 140 return cleanup(session); 141 } 142 143 bool VersionBlobHandler::cleanup(uint16_t session) 144 { 145 try 146 { 147 auto& pack = *sessionToBlob.at(session); 148 pack.actions->onOpen->abort(); 149 pack.blobState = static_cast<blobs::StateFlags>(0); 150 sessionToBlob.erase(session); 151 return true; 152 } 153 catch (const std::out_of_range& e) 154 { 155 return false; 156 } 157 } 158 } // namespace ipmi_flash 159