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 <blobs-ipmid/manager.hpp> 18 #include <memory> 19 #include <string> 20 #include <vector> 21 22 namespace blobs 23 { 24 25 void BlobManager::incrementOpen(const std::string& path) 26 { 27 if (path.empty()) 28 { 29 return; 30 } 31 32 openFiles[path] += 1; 33 } 34 35 void 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 56 int 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 68 bool 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 79 uint32_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 95 std::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 106 bool 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 142 GenericBlobInterface* 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 159 GenericBlobInterface* 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 170 SessionInfo* 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 184 std::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 195 bool 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 209 bool 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 223 bool 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 236 bool 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 257 std::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 278 bool 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 299 bool 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 319 bool 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 } 347 348 static std::unique_ptr<BlobManager> manager; 349 350 ManagerInterface* getBlobManager() 351 { 352 if (manager == nullptr) 353 { 354 manager = std::make_unique<BlobManager>(); 355 } 356 357 return manager.get(); 358 } 359 360 } // namespace blobs 361