blob: 75ba9401037e477f10952059cb5dfb95656b34c3 [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 }
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
108std::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
148bool VersionBlobHandler::close(uint16_t session)
149{
150 return cleanup(session);
151}
152
153bool VersionBlobHandler::stat(uint16_t session, blobs::BlobMeta* meta)
154{
155 return false;
156}
157
158bool VersionBlobHandler::expire(uint16_t session)
159{
160 return cleanup(session);
161}
162
163bool 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