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