blob: 9a87b4fef8e3c2e00c053799d0bc22a5f2a71b61 [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 Ventureef3aead2018-09-12 08:53:29 -070018#include <string>
19#include <vector>
20
21namespace blobs
22{
23
24void BlobManager::incrementOpen(const std::string& path)
25{
26 if (path.empty())
27 {
28 return;
29 }
30
31 openFiles[path] += 1;
32}
33
34void BlobManager::decrementOpen(const std::string& path)
35{
36 if (path.empty())
37 {
38 return;
39 }
40
41 /* TODO(venture): Check into the iterator from find, does it makes sense
42 * to just update it directly? */
43 auto entry = openFiles.find(path);
44 if (entry != openFiles.end())
45 {
46 /* found it, decrement it and remove it if 0. */
47 openFiles[path] -= 1;
48 if (openFiles[path] == 0)
49 {
50 openFiles.erase(path);
51 }
52 }
53}
54
55int BlobManager::getOpen(const std::string& path) const
56{
57 /* No need to input check on the read-only call. */
58 auto entry = openFiles.find(path);
59 if (entry != openFiles.end())
60 {
61 return entry->second;
62 }
63
64 return 0;
65}
66
67bool BlobManager::registerHandler(std::unique_ptr<GenericBlobInterface> handler)
68{
69 if (!handler)
70 {
71 return false;
72 }
73
74 handlers.push_back(std::move(handler));
75 return true;
76}
77
78uint32_t BlobManager::buildBlobList()
79{
80 /* Clear out the current list (IPMI handler is presently single-threaded).
81 */
82 ids.clear();
83
84 /* Grab the list of blobs and extend the local list */
85 for (auto& h : handlers)
86 {
87 std::vector<std::string> blobs = h->getBlobIds();
88 ids.insert(ids.end(), blobs.begin(), blobs.end());
89 }
90
91 return ids.size();
92}
93
94std::string BlobManager::getBlobId(uint32_t index)
95{
96 /* Range check. */
97 if (index >= ids.size())
98 {
99 return "";
100 }
101
102 return ids[index];
103}
104
105bool BlobManager::open(uint16_t flags, const std::string& path,
106 uint16_t* session)
107{
108 GenericBlobInterface* handler = getHandler(path);
109
110 /* No handler found. */
111 if (!handler)
112 {
113 return false;
114 }
115
116 /* No sessions availabe... */
117 if (!getSession(session))
118 {
119 return false;
120 }
121
122 /* Verify flags - must be at least read or write */
123 if (!(flags & (OpenFlags::read | OpenFlags::write)))
124 {
125 /* Neither read not write set, which means calls to Read/Write will
126 * reject. */
127 return false;
128 }
129
130 if (!handler->open(*session, flags, path))
131 {
132 return false;
133 }
134
135 /* Associate session with handler */
136 sessions[*session] = SessionInfo(path, handler, flags);
137 incrementOpen(path);
138 return true;
139}
140
141GenericBlobInterface* BlobManager::getHandler(const std::string& path)
142{
143 /* Find a handler. */
144 GenericBlobInterface* handler = nullptr;
145
146 for (auto& h : handlers)
147 {
148 if (h->canHandleBlob(path))
149 {
150 handler = h.get();
151 break;
152 }
153 }
154
155 return handler;
156}
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
273 /* Try reading from it. */
274 return info->handler->read(session, offset, requestedSize);
275}
276
277bool BlobManager::write(uint16_t session, uint32_t offset,
278 const std::vector<uint8_t>& data)
279{
280 SessionInfo* info = getSessionInfo(session);
281
282 /* No session found. */
283 if (!info)
284 {
285 return false;
286 }
287
288 /* Check flags. */
289 if (!(info->flags & OpenFlags::write))
290 {
291 return false;
292 }
293
294 /* Try writing to it. */
295 return info->handler->write(session, offset, data);
296}
297
298bool BlobManager::deleteBlob(const std::string& path)
299{
300 GenericBlobInterface* handler = getHandler(path);
301
302 /* No handler found. */
303 if (!handler)
304 {
305 return false;
306 }
307
308 /* Check if the file has any open handles. */
309 if (getOpen(path) > 0)
310 {
311 return false;
312 }
313
314 /* Try deleting it. */
315 return handler->deleteBlob(path);
316}
317
318bool BlobManager::getSession(uint16_t* sess)
319{
320 uint16_t tries = 0;
321 uint16_t lsess;
322
323 if (!sess)
324 {
325 return false;
326 }
327
328 /* This is not meant to fail as you have 64KiB values available. */
329
330 /* TODO(venture): We could just count the keys in the session map to know
331 * if it's full.
332 */
333 do
334 {
335 lsess = next++;
336 if (!sessions.count(lsess))
337 {
338 /* value not in use, return it. */
339 (*sess) = lsess;
340 return true;
341 }
342 } while (++tries < 0xffff);
343
344 return false;
345}
346} // namespace blobs