blob: 639ca2d8ed233e3fff0795e30a1bd2e162bdd1d8 [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
158GenericBlobInterface* BlobManager::getHandler(uint16_t session)
159{
160 auto item = sessions.find(session);
161 if (item == sessions.end())
162 {
163 return nullptr;
164 }
165
166 return item->second.handler;
167}
168
169SessionInfo* BlobManager::getSessionInfo(uint16_t session)
170{
171 auto item = sessions.find(session);
172 if (item == sessions.end())
173 {
174 return nullptr;
175 }
176
177 /* If we go to multi-threaded, this pointer can be invalidated and this
178 * method will need to change.
179 */
180 return &item->second;
181}
182
183std::string BlobManager::getPath(uint16_t session) const
184{
185 auto item = sessions.find(session);
186 if (item == sessions.end())
187 {
188 return "";
189 }
190
191 return item->second.blobId;
192}
193
194bool BlobManager::stat(const std::string& path, struct BlobMeta* meta)
195{
196 /* meta should never be NULL. */
197 GenericBlobInterface* handler = getHandler(path);
198
199 /* No handler found. */
200 if (!handler)
201 {
202 return false;
203 }
204
205 return handler->stat(path, meta);
206}
207
208bool BlobManager::stat(uint16_t session, struct BlobMeta* meta)
209{
210 /* meta should never be NULL. */
211 GenericBlobInterface* handler = getHandler(session);
212
213 /* No handler found. */
214 if (!handler)
215 {
216 return false;
217 }
218
219 return handler->stat(session, meta);
220}
221
222bool BlobManager::commit(uint16_t session, const std::vector<uint8_t>& data)
223{
224 GenericBlobInterface* handler = getHandler(session);
225
226 /* No handler found. */
227 if (!handler)
228 {
229 return false;
230 }
231
232 return handler->commit(session, data);
233}
234
235bool BlobManager::close(uint16_t session)
236{
237 GenericBlobInterface* handler = getHandler(session);
238
239 /* No handler found. */
240 if (!handler)
241 {
242 return false;
243 }
244
245 /* Handler returns failure */
246 if (!handler->close(session))
247 {
248 return false;
249 }
250
251 sessions.erase(session);
252 decrementOpen(getPath(session));
253 return true;
254}
255
256std::vector<uint8_t> BlobManager::read(uint16_t session, uint32_t offset,
257 uint32_t requestedSize)
258{
259 SessionInfo* info = getSessionInfo(session);
260
261 /* No session found. */
262 if (!info)
263 {
264 return std::vector<uint8_t>();
265 }
266
267 /* Check flags. */
268 if (!(info->flags & OpenFlags::read))
269 {
270 return std::vector<uint8_t>();
271 }
272
Patrick Venture86c87f52019-02-01 14:44:15 -0800273 /* TODO: Currently, configure_ac isn't finding libuserlayer, w.r.t the
274 * symbols I need.
275 */
276
277 /** The channel to use for now.
278 * TODO: We will receive this information through the IPMI message call.
279 */
280 // const int ipmiChannel = ipmi::currentChNum;
281 /** This information is transport specific.
282 * TODO: We need a way to know this dynamically.
283 * on BT, 4 bytes of header, and 1 reply code.
284 */
285 // uint32_t maxTransportSize = ipmi::getChannelMaxTransferSize(ipmiChannel);
286
Patrick Ventureef3aead2018-09-12 08:53:29 -0700287 /* Try reading from it. */
Patrick Venture86c87f52019-02-01 14:44:15 -0800288 return info->handler->read(session, offset,
289 std::min(maximumReadSize, requestedSize));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700290}
291
292bool BlobManager::write(uint16_t session, uint32_t offset,
293 const std::vector<uint8_t>& data)
294{
295 SessionInfo* info = getSessionInfo(session);
296
297 /* No session found. */
298 if (!info)
299 {
300 return false;
301 }
302
303 /* Check flags. */
304 if (!(info->flags & OpenFlags::write))
305 {
306 return false;
307 }
308
309 /* Try writing to it. */
310 return info->handler->write(session, offset, data);
311}
312
313bool BlobManager::deleteBlob(const std::string& path)
314{
315 GenericBlobInterface* handler = getHandler(path);
316
317 /* No handler found. */
318 if (!handler)
319 {
320 return false;
321 }
322
323 /* Check if the file has any open handles. */
324 if (getOpen(path) > 0)
325 {
326 return false;
327 }
328
329 /* Try deleting it. */
330 return handler->deleteBlob(path);
331}
332
Patrick Venture5c4b17b2018-10-04 10:32:22 -0700333bool BlobManager::writeMeta(uint16_t session, uint32_t offset,
334 const std::vector<uint8_t>& data)
335{
336 SessionInfo* info = getSessionInfo(session);
337
338 /* No session found. */
339 if (!info)
340 {
341 return false;
342 }
343
344 /* Try writing metadata to it. */
345 return info->handler->writeMeta(session, offset, data);
346}
347
Patrick Ventureef3aead2018-09-12 08:53:29 -0700348bool BlobManager::getSession(uint16_t* sess)
349{
350 uint16_t tries = 0;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700351
352 if (!sess)
353 {
354 return false;
355 }
356
357 /* This is not meant to fail as you have 64KiB values available. */
358
359 /* TODO(venture): We could just count the keys in the session map to know
360 * if it's full.
361 */
362 do
363 {
Patrick Venturec9ad5ff2018-10-12 17:05:49 -0700364 uint16_t lsess = next++;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700365 if (!sessions.count(lsess))
366 {
367 /* value not in use, return it. */
368 (*sess) = lsess;
369 return true;
370 }
371 } while (++tries < 0xffff);
372
373 return false;
374}
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700375
376static std::unique_ptr<BlobManager> manager;
377
Patrick Venture73eb6872018-10-01 18:37:34 -0700378ManagerInterface* getBlobManager()
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700379{
380 if (manager == nullptr)
381 {
382 manager = std::make_unique<BlobManager>();
383 }
384
385 return manager.get();
386}
387
Patrick Ventureef3aead2018-09-12 08:53:29 -0700388} // namespace blobs