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