blob: 684f20c15b60b0e09b1e80df84da07df82822097 [file] [log] [blame]
Patrick Ventureef3aead2018-09-12 08:53:29 -07001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Patrick Venturecd8dab42019-01-15 19:57:38 -080017#include "manager.hpp"
18
Patrick Venturee50d4e42018-10-23 09:50:27 -070019#include <algorithm>
Patrick Ventureb3e07e22018-09-27 15:11:57 -070020#include <memory>
Patrick Ventureef3aead2018-09-12 08:53:29 -070021#include <string>
22#include <vector>
23
24namespace blobs
25{
26
27void BlobManager::incrementOpen(const std::string& path)
28{
29 if (path.empty())
30 {
31 return;
32 }
33
34 openFiles[path] += 1;
35}
36
37void BlobManager::decrementOpen(const std::string& path)
38{
39 if (path.empty())
40 {
41 return;
42 }
43
44 /* TODO(venture): Check into the iterator from find, does it makes sense
45 * to just update it directly? */
46 auto entry = openFiles.find(path);
47 if (entry != openFiles.end())
48 {
49 /* found it, decrement it and remove it if 0. */
50 openFiles[path] -= 1;
51 if (openFiles[path] == 0)
52 {
53 openFiles.erase(path);
54 }
55 }
56}
57
58int BlobManager::getOpen(const std::string& path) const
59{
60 /* No need to input check on the read-only call. */
61 auto entry = openFiles.find(path);
62 if (entry != openFiles.end())
63 {
64 return entry->second;
65 }
66
67 return 0;
68}
69
70bool BlobManager::registerHandler(std::unique_ptr<GenericBlobInterface> handler)
71{
72 if (!handler)
73 {
74 return false;
75 }
76
77 handlers.push_back(std::move(handler));
78 return true;
79}
80
81uint32_t BlobManager::buildBlobList()
82{
83 /* Clear out the current list (IPMI handler is presently single-threaded).
84 */
85 ids.clear();
86
87 /* Grab the list of blobs and extend the local list */
Patrick Venturea6e21a02018-10-23 09:45:04 -070088 for (const auto& h : handlers)
Patrick Ventureef3aead2018-09-12 08:53:29 -070089 {
90 std::vector<std::string> blobs = h->getBlobIds();
91 ids.insert(ids.end(), blobs.begin(), blobs.end());
92 }
93
94 return ids.size();
95}
96
97std::string BlobManager::getBlobId(uint32_t index)
98{
99 /* Range check. */
100 if (index >= ids.size())
101 {
102 return "";
103 }
104
105 return ids[index];
106}
107
108bool BlobManager::open(uint16_t flags, const std::string& path,
109 uint16_t* session)
110{
111 GenericBlobInterface* handler = getHandler(path);
112
113 /* No handler found. */
114 if (!handler)
115 {
116 return false;
117 }
118
Patrick Venture2f581512019-01-10 09:30:36 -0800119 /* No sessions available... */
Patrick Ventureef3aead2018-09-12 08:53:29 -0700120 if (!getSession(session))
121 {
122 return false;
123 }
124
125 /* Verify flags - must be at least read or write */
126 if (!(flags & (OpenFlags::read | OpenFlags::write)))
127 {
128 /* Neither read not write set, which means calls to Read/Write will
129 * reject. */
130 return false;
131 }
132
133 if (!handler->open(*session, flags, path))
134 {
135 return false;
136 }
137
138 /* Associate session with handler */
139 sessions[*session] = SessionInfo(path, handler, flags);
140 incrementOpen(path);
141 return true;
142}
143
144GenericBlobInterface* BlobManager::getHandler(const std::string& path)
145{
146 /* Find a handler. */
Patrick Venturee50d4e42018-10-23 09:50:27 -0700147 auto h = std::find_if(
148 handlers.begin(), handlers.end(),
149 [&path](const auto& iter) { return (iter->canHandleBlob(path)); });
150 if (h != handlers.end())
Patrick Ventureef3aead2018-09-12 08:53:29 -0700151 {
Patrick Venturee50d4e42018-10-23 09:50:27 -0700152 return h->get();
Patrick Ventureef3aead2018-09-12 08:53:29 -0700153 }
154
Patrick Venturee50d4e42018-10-23 09:50:27 -0700155 return nullptr;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700156}
157
Patrick Ventureef3aead2018-09-12 08:53:29 -0700158std::string BlobManager::getPath(uint16_t session) const
159{
160 auto item = sessions.find(session);
161 if (item == sessions.end())
162 {
163 return "";
164 }
165
166 return item->second.blobId;
167}
168
Patrick Venture8bc11772019-06-04 07:20:24 -0700169bool BlobManager::stat(const std::string& path, BlobMeta* meta)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700170{
171 /* meta should never be NULL. */
172 GenericBlobInterface* handler = getHandler(path);
173
174 /* No handler found. */
175 if (!handler)
176 {
177 return false;
178 }
179
180 return handler->stat(path, meta);
181}
182
Patrick Venture8bc11772019-06-04 07:20:24 -0700183bool BlobManager::stat(uint16_t session, BlobMeta* meta)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700184{
Kun Yic892f4a2019-11-19 13:42:46 -0800185 if (auto handler = getActionHandle(session))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700186 {
Kun Yic892f4a2019-11-19 13:42:46 -0800187 return handler->stat(session, meta);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700188 }
Kun Yic892f4a2019-11-19 13:42:46 -0800189 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700190}
191
192bool BlobManager::commit(uint16_t session, const std::vector<uint8_t>& data)
193{
Kun Yic892f4a2019-11-19 13:42:46 -0800194 if (auto handler = getActionHandle(session))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700195 {
Kun Yic892f4a2019-11-19 13:42:46 -0800196 return handler->commit(session, data);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700197 }
Kun Yic892f4a2019-11-19 13:42:46 -0800198 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700199}
200
201bool BlobManager::close(uint16_t session)
202{
Kun Yic892f4a2019-11-19 13:42:46 -0800203 if (auto handler = getActionHandle(session))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700204 {
Kun Yic892f4a2019-11-19 13:42:46 -0800205 if (!handler->close(session))
206 {
207 return false;
208 }
209 sessions.erase(session);
210 decrementOpen(getPath(session));
211 return true;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700212 }
Kun Yic892f4a2019-11-19 13:42:46 -0800213 return false;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700214}
215
216std::vector<uint8_t> BlobManager::read(uint16_t session, uint32_t offset,
217 uint32_t requestedSize)
218{
Patrick Venture86c87f52019-02-01 14:44:15 -0800219 /* TODO: Currently, configure_ac isn't finding libuserlayer, w.r.t the
220 * symbols I need.
221 */
222
223 /** The channel to use for now.
224 * TODO: We will receive this information through the IPMI message call.
225 */
226 // const int ipmiChannel = ipmi::currentChNum;
227 /** This information is transport specific.
228 * TODO: We need a way to know this dynamically.
229 * on BT, 4 bytes of header, and 1 reply code.
230 */
231 // uint32_t maxTransportSize = ipmi::getChannelMaxTransferSize(ipmiChannel);
232
Kun Yic892f4a2019-11-19 13:42:46 -0800233 if (auto handler = getActionHandle(session, OpenFlags::read))
234 {
235 return handler->read(session, offset,
236 std::min(maximumReadSize, requestedSize));
237 }
238 return {};
Patrick Ventureef3aead2018-09-12 08:53:29 -0700239}
240
241bool BlobManager::write(uint16_t session, uint32_t offset,
242 const std::vector<uint8_t>& data)
243{
Kun Yic892f4a2019-11-19 13:42:46 -0800244 if (auto handler = getActionHandle(session, OpenFlags::write))
Patrick Ventureef3aead2018-09-12 08:53:29 -0700245 {
Kun Yic892f4a2019-11-19 13:42:46 -0800246 return handler->write(session, offset, data);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700247 }
Kun Yic892f4a2019-11-19 13:42:46 -0800248 return {};
Patrick Ventureef3aead2018-09-12 08:53:29 -0700249}
250
251bool BlobManager::deleteBlob(const std::string& path)
252{
253 GenericBlobInterface* handler = getHandler(path);
254
255 /* No handler found. */
256 if (!handler)
257 {
258 return false;
259 }
260
261 /* Check if the file has any open handles. */
262 if (getOpen(path) > 0)
263 {
264 return false;
265 }
266
267 /* Try deleting it. */
268 return handler->deleteBlob(path);
269}
270
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700271bool BlobManager::writeMeta(uint16_t session, uint32_t offset,
272 const std::vector<uint8_t>& data)
273{
Kun Yic892f4a2019-11-19 13:42:46 -0800274 if (auto handler = getActionHandle(session))
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700275 {
Kun Yic892f4a2019-11-19 13:42:46 -0800276 return handler->writeMeta(session, offset, data);
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700277 }
Kun Yic892f4a2019-11-19 13:42:46 -0800278 return false;
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700279}
280
Patrick Ventureef3aead2018-09-12 08:53:29 -0700281bool BlobManager::getSession(uint16_t* sess)
282{
283 uint16_t tries = 0;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700284
285 if (!sess)
286 {
287 return false;
288 }
289
290 /* This is not meant to fail as you have 64KiB values available. */
291
292 /* TODO(venture): We could just count the keys in the session map to know
293 * if it's full.
294 */
295 do
296 {
Patrick Venturec9ad5ff2018-10-12 17:05:49 -0700297 uint16_t lsess = next++;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700298 if (!sessions.count(lsess))
299 {
300 /* value not in use, return it. */
301 (*sess) = lsess;
302 return true;
303 }
304 } while (++tries < 0xffff);
305
306 return false;
307}
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700308
309static std::unique_ptr<BlobManager> manager;
310
Patrick Venture73eb6872018-10-01 18:37:34 -0700311ManagerInterface* getBlobManager()
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700312{
313 if (manager == nullptr)
314 {
315 manager = std::make_unique<BlobManager>();
316 }
317
318 return manager.get();
319}
320
Patrick Ventureef3aead2018-09-12 08:53:29 -0700321} // namespace blobs