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