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 sessionToBlob[session] = &v; 74 75 if (v.blobState == blobs::StateFlags::open_read) 76 { 77 fprintf(stderr, "open %s fail: blob already opened for read\n", 78 path.c_str()); 79 cleanup(session); 80 return false; 81 } 82 if (v.actions->onOpen->trigger() == false) 83 { 84 fprintf(stderr, "open %s fail: onOpen trigger failed\n", path.c_str()); 85 cleanup(session); 86 return false; 87 } 88 v.blobState = blobs::StateFlags::open_read; 89 return true; 90 } 91 92 std::vector<uint8_t> VersionBlobHandler::read(uint16_t session, uint32_t offset, 93 uint32_t requestedSize) 94 { 95 BlobInfo* pack; 96 try 97 { 98 pack = sessionToBlob.at(session); 99 } 100 catch (const std::out_of_range& e) 101 { 102 return {}; 103 } 104 /* onOpen trigger must be successful, otherwise potential 105 * for stale data to be read 106 */ 107 if (pack->actions->onOpen->status() != ActionStatus::success) 108 { 109 fprintf(stderr, "read failed: onOpen trigger not successful\n"); 110 return {}; 111 } 112 if (!pack->handler->open("don't care", std::ios::in)) 113 { 114 fprintf(stderr, "read failed: file open unsuccessful blob=%s\n", 115 pack->blobId.c_str()); 116 return {}; 117 } 118 auto d = pack->handler->read(offset, requestedSize); 119 if (!d) 120 { 121 fprintf(stderr, "read failed: unable to read file for blob %s\n", 122 pack->blobId.c_str()); 123 pack->handler->close(); 124 return {}; 125 } 126 pack->handler->close(); 127 return *d; 128 } 129 130 bool VersionBlobHandler::close(uint16_t session) 131 { 132 return cleanup(session); 133 } 134 135 bool VersionBlobHandler::stat(uint16_t session, blobs::BlobMeta* meta) 136 { 137 return false; 138 } 139 140 bool VersionBlobHandler::expire(uint16_t session) 141 { 142 return cleanup(session); 143 } 144 145 bool VersionBlobHandler::cleanup(uint16_t session) 146 { 147 try 148 { 149 auto& pack = *sessionToBlob.at(session); 150 if (pack.actions->onOpen->status() == ActionStatus::running) 151 { 152 pack.actions->onOpen->abort(); 153 } 154 pack.blobState = static_cast<blobs::StateFlags>(0); 155 sessionToBlob.erase(session); 156 return true; 157 } 158 catch (const std::out_of_range& e) 159 { 160 return false; 161 } 162 } 163 } // namespace ipmi_flash 164