blob: 6a94c1a19a73695a9538868a3032cdcf7c8adfae [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 Ventureaceb4ba2018-09-27 14:50:37 -070017#include <blobs-ipmid/manager.hpp>
Patrick Ventureb3e07e22018-09-27 15:11:57 -070018#include <memory>
Patrick Ventureef3aead2018-09-12 08:53:29 -070019#include <string>
20#include <vector>
21
22namespace blobs
23{
24
25void BlobManager::incrementOpen(const std::string& path)
26{
27 if (path.empty())
28 {
29 return;
30 }
31
32 openFiles[path] += 1;
33}
34
35void BlobManager::decrementOpen(const std::string& path)
36{
37 if (path.empty())
38 {
39 return;
40 }
41
42 /* TODO(venture): Check into the iterator from find, does it makes sense
43 * to just update it directly? */
44 auto entry = openFiles.find(path);
45 if (entry != openFiles.end())
46 {
47 /* found it, decrement it and remove it if 0. */
48 openFiles[path] -= 1;
49 if (openFiles[path] == 0)
50 {
51 openFiles.erase(path);
52 }
53 }
54}
55
56int BlobManager::getOpen(const std::string& path) const
57{
58 /* No need to input check on the read-only call. */
59 auto entry = openFiles.find(path);
60 if (entry != openFiles.end())
61 {
62 return entry->second;
63 }
64
65 return 0;
66}
67
68bool BlobManager::registerHandler(std::unique_ptr<GenericBlobInterface> handler)
69{
70 if (!handler)
71 {
72 return false;
73 }
74
75 handlers.push_back(std::move(handler));
76 return true;
77}
78
79uint32_t BlobManager::buildBlobList()
80{
81 /* Clear out the current list (IPMI handler is presently single-threaded).
82 */
83 ids.clear();
84
85 /* Grab the list of blobs and extend the local list */
86 for (auto& h : handlers)
87 {
88 std::vector<std::string> blobs = h->getBlobIds();
89 ids.insert(ids.end(), blobs.begin(), blobs.end());
90 }
91
92 return ids.size();
93}
94
95std::string BlobManager::getBlobId(uint32_t index)
96{
97 /* Range check. */
98 if (index >= ids.size())
99 {
100 return "";
101 }
102
103 return ids[index];
104}
105
106bool BlobManager::open(uint16_t flags, const std::string& path,
107 uint16_t* session)
108{
109 GenericBlobInterface* handler = getHandler(path);
110
111 /* No handler found. */
112 if (!handler)
113 {
114 return false;
115 }
116
117 /* No sessions availabe... */
118 if (!getSession(session))
119 {
120 return false;
121 }
122
123 /* Verify flags - must be at least read or write */
124 if (!(flags & (OpenFlags::read | OpenFlags::write)))
125 {
126 /* Neither read not write set, which means calls to Read/Write will
127 * reject. */
128 return false;
129 }
130
131 if (!handler->open(*session, flags, path))
132 {
133 return false;
134 }
135
136 /* Associate session with handler */
137 sessions[*session] = SessionInfo(path, handler, flags);
138 incrementOpen(path);
139 return true;
140}
141
142GenericBlobInterface* BlobManager::getHandler(const std::string& path)
143{
144 /* Find a handler. */
145 GenericBlobInterface* handler = nullptr;
146
147 for (auto& h : handlers)
148 {
149 if (h->canHandleBlob(path))
150 {
151 handler = h.get();
152 break;
153 }
154 }
155
156 return handler;
157}
158
159GenericBlobInterface* BlobManager::getHandler(uint16_t session)
160{
161 auto item = sessions.find(session);
162 if (item == sessions.end())
163 {
164 return nullptr;
165 }
166
167 return item->second.handler;
168}
169
170SessionInfo* BlobManager::getSessionInfo(uint16_t session)
171{
172 auto item = sessions.find(session);
173 if (item == sessions.end())
174 {
175 return nullptr;
176 }
177
178 /* If we go to multi-threaded, this pointer can be invalidated and this
179 * method will need to change.
180 */
181 return &item->second;
182}
183
184std::string BlobManager::getPath(uint16_t session) const
185{
186 auto item = sessions.find(session);
187 if (item == sessions.end())
188 {
189 return "";
190 }
191
192 return item->second.blobId;
193}
194
195bool BlobManager::stat(const std::string& path, struct BlobMeta* meta)
196{
197 /* meta should never be NULL. */
198 GenericBlobInterface* handler = getHandler(path);
199
200 /* No handler found. */
201 if (!handler)
202 {
203 return false;
204 }
205
206 return handler->stat(path, meta);
207}
208
209bool BlobManager::stat(uint16_t session, struct BlobMeta* meta)
210{
211 /* meta should never be NULL. */
212 GenericBlobInterface* handler = getHandler(session);
213
214 /* No handler found. */
215 if (!handler)
216 {
217 return false;
218 }
219
220 return handler->stat(session, meta);
221}
222
223bool BlobManager::commit(uint16_t session, const std::vector<uint8_t>& data)
224{
225 GenericBlobInterface* handler = getHandler(session);
226
227 /* No handler found. */
228 if (!handler)
229 {
230 return false;
231 }
232
233 return handler->commit(session, data);
234}
235
236bool BlobManager::close(uint16_t session)
237{
238 GenericBlobInterface* handler = getHandler(session);
239
240 /* No handler found. */
241 if (!handler)
242 {
243 return false;
244 }
245
246 /* Handler returns failure */
247 if (!handler->close(session))
248 {
249 return false;
250 }
251
252 sessions.erase(session);
253 decrementOpen(getPath(session));
254 return true;
255}
256
257std::vector<uint8_t> BlobManager::read(uint16_t session, uint32_t offset,
258 uint32_t requestedSize)
259{
260 SessionInfo* info = getSessionInfo(session);
261
262 /* No session found. */
263 if (!info)
264 {
265 return std::vector<uint8_t>();
266 }
267
268 /* Check flags. */
269 if (!(info->flags & OpenFlags::read))
270 {
271 return std::vector<uint8_t>();
272 }
273
274 /* Try reading from it. */
275 return info->handler->read(session, offset, requestedSize);
276}
277
278bool BlobManager::write(uint16_t session, uint32_t offset,
279 const std::vector<uint8_t>& data)
280{
281 SessionInfo* info = getSessionInfo(session);
282
283 /* No session found. */
284 if (!info)
285 {
286 return false;
287 }
288
289 /* Check flags. */
290 if (!(info->flags & OpenFlags::write))
291 {
292 return false;
293 }
294
295 /* Try writing to it. */
296 return info->handler->write(session, offset, data);
297}
298
299bool BlobManager::deleteBlob(const std::string& path)
300{
301 GenericBlobInterface* handler = getHandler(path);
302
303 /* No handler found. */
304 if (!handler)
305 {
306 return false;
307 }
308
309 /* Check if the file has any open handles. */
310 if (getOpen(path) > 0)
311 {
312 return false;
313 }
314
315 /* Try deleting it. */
316 return handler->deleteBlob(path);
317}
318
319bool BlobManager::getSession(uint16_t* sess)
320{
321 uint16_t tries = 0;
322 uint16_t lsess;
323
324 if (!sess)
325 {
326 return false;
327 }
328
329 /* This is not meant to fail as you have 64KiB values available. */
330
331 /* TODO(venture): We could just count the keys in the session map to know
332 * if it's full.
333 */
334 do
335 {
336 lsess = next++;
337 if (!sessions.count(lsess))
338 {
339 /* value not in use, return it. */
340 (*sess) = lsess;
341 return true;
342 }
343 } while (++tries < 0xffff);
344
345 return false;
346}
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700347
348static std::unique_ptr<BlobManager> manager;
349
Patrick Venture73eb6872018-10-01 18:37:34 -0700350ManagerInterface* getBlobManager()
Patrick Ventureb3e07e22018-09-27 15:11:57 -0700351{
352 if (manager == nullptr)
353 {
354 manager = std::make_unique<BlobManager>();
355 }
356
357 return manager.get();
358}
359
Patrick Ventureef3aead2018-09-12 08:53:29 -0700360} // namespace blobs