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