1 /* 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 17 #include "manager.hpp" 18 19 #include <algorithm> 20 #include <memory> 21 #include <string> 22 #include <vector> 23 24 namespace blobs 25 { 26 27 void BlobManager::incrementOpen(const std::string& path) 28 { 29 if (path.empty()) 30 { 31 return; 32 } 33 34 openFiles[path] += 1; 35 } 36 37 void 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 58 int 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 70 bool 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 81 uint32_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 */ 88 for (const auto& h : handlers) 89 { 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 97 std::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 108 bool 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 119 /* No sessions available... */ 120 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 144 GenericBlobInterface* BlobManager::getHandler(const std::string& path) 145 { 146 /* Find a handler. */ 147 auto h = std::find_if( 148 handlers.begin(), handlers.end(), 149 [&path](const auto& iter) { return (iter->canHandleBlob(path)); }); 150 if (h != handlers.end()) 151 { 152 return h->get(); 153 } 154 155 return nullptr; 156 } 157 158 GenericBlobInterface* 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 169 SessionInfo* 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 183 std::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 194 bool BlobManager::stat(const std::string& path, 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 208 bool BlobManager::stat(uint16_t session, 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 222 bool 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 235 bool 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 256 std::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 /* 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 287 /* Try reading from it. */ 288 return info->handler->read(session, offset, 289 std::min(maximumReadSize, requestedSize)); 290 } 291 292 bool 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 313 bool 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 333 bool 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 348 bool BlobManager::getSession(uint16_t* sess) 349 { 350 uint16_t tries = 0; 351 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 { 364 uint16_t lsess = next++; 365 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 } 375 376 static std::unique_ptr<BlobManager> manager; 377 378 ManagerInterface* getBlobManager() 379 { 380 if (manager == nullptr) 381 { 382 manager = std::make_unique<BlobManager>(); 383 } 384 385 return manager.get(); 386 } 387 388 } // namespace blobs 389