blob: 32b29da380901aec64551f9a6db7440f3d0bfffc [file] [log] [blame]
Jason Lingc78bfc82020-11-05 18:58:16 -08001#include "version_handler.hpp"
2
3#include <stdexcept>
4namespace ipmi_flash
5{
6std::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
27bool VersionBlobHandler::canHandleBlob(const std::string& path)
28{
29 return (std::find(blobIds.begin(), blobIds.end(), path) != blobIds.end());
30}
31
32std::vector<std::string> VersionBlobHandler::getBlobIds()
33{
34 return blobIds;
35}
36
37/**
38 * deleteBlob - does nothing, always fails
39 */
40bool VersionBlobHandler::deleteBlob(const std::string& path)
41{
42 return false;
43}
44
45bool 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
54bool 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 }
Jason Lingc78bfc82020-11-05 18:58:16 -080073
74 try
75 {
76 auto& v = versionInfoMap.at(path);
77 if (v.blobState == blobs::StateFlags::open_read)
78 {
79 cleanup(session);
80 fprintf(stderr, "open %s fail: blob already opened for read\n",
81 path.c_str());
82 return false;
83 }
84 if (v.actionPack->onOpen->trigger() == false)
85 {
86 fprintf(stderr, "open %s fail: onOpen trigger failed\n",
87 path.c_str());
88 cleanup(session);
89 return false;
90 }
91 v.blobState = blobs::StateFlags::open_read;
92 return true;
93 }
94 catch (const std::out_of_range& e)
95 {
96 fprintf(stderr, "open %s fail, exception:%s\n", path.c_str(), e.what());
97 cleanup(session);
98 return false;
99 }
100}
101
102std::vector<uint8_t> VersionBlobHandler::read(uint16_t session, uint32_t offset,
103 uint32_t requestedSize)
104{
105 std::string* blobName;
106 VersionInfoPack* pack;
107 try
108 {
109 blobName = &sessionToBlob.at(session);
110 pack = &versionInfoMap.at(*blobName);
111 }
112 catch (const std::out_of_range& e)
113 {
114 return {};
115 }
116 /* onOpen trigger must be successful, otherwise potential
117 * for stale data to be read
118 */
119 if (pack->actionPack->onOpen->status() != ActionStatus::success)
120 {
121 fprintf(stderr, "read failed: onOpen trigger not successful\n");
122 return {};
123 }
124 if (!pack->imageHandler->open("don't care", std::ios::in))
125 {
126 fprintf(stderr, "read failed: file open unsuccessful blob=%s\n",
127 blobName->c_str());
128 return {};
129 }
130 auto d = pack->imageHandler->read(offset, requestedSize);
131 if (!d)
132 {
133 fprintf(stderr, "read failed: unable to read file for blob %s\n",
134 blobName->c_str());
135 pack->imageHandler->close();
136 return {};
137 }
138 pack->imageHandler->close();
139 return *d;
140}
141
142bool VersionBlobHandler::close(uint16_t session)
143{
144 return cleanup(session);
145}
146
147bool VersionBlobHandler::stat(uint16_t session, blobs::BlobMeta* meta)
148{
149 return false;
150}
151
152bool VersionBlobHandler::expire(uint16_t session)
153{
154 return cleanup(session);
155}
156
157bool VersionBlobHandler::cleanup(uint16_t session)
158{
159 try
160 {
161 const auto& blobName = sessionToBlob.at(session);
162 auto& pack = versionInfoMap.at(blobName);
163 if (pack.actionPack->onOpen->status() == ActionStatus::running)
164 {
165 pack.actionPack->onOpen->abort();
166 }
167 pack.blobState = static_cast<blobs::StateFlags>(0);
168 sessionToBlob.erase(session);
169 return true;
170 }
171 catch (const std::out_of_range& e)
172 {
173 return false;
174 }
175}
176} // namespace ipmi_flash