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