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 <string> 19 #include <vector> 20 21 namespace blobs 22 { 23 24 void BlobManager::incrementOpen(const std::string& path) 25 { 26 if (path.empty()) 27 { 28 return; 29 } 30 31 openFiles[path] += 1; 32 } 33 34 void 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 55 int 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 67 bool 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 78 uint32_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 94 std::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 105 bool 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 141 GenericBlobInterface* 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 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, 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 208 bool 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 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 /* Try reading from it. */ 274 return info->handler->read(session, offset, requestedSize); 275 } 276 277 bool 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 298 bool 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 318 bool 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 347