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 std::string BlobManager::getPath(uint16_t session) const 159 { 160 auto item = sessions.find(session); 161 if (item == sessions.end()) 162 { 163 return ""; 164 } 165 166 return item->second.blobId; 167 } 168 169 bool BlobManager::stat(const std::string& path, BlobMeta* meta) 170 { 171 /* meta should never be NULL. */ 172 GenericBlobInterface* handler = getHandler(path); 173 174 /* No handler found. */ 175 if (!handler) 176 { 177 return false; 178 } 179 180 return handler->stat(path, meta); 181 } 182 183 bool BlobManager::stat(uint16_t session, BlobMeta* meta) 184 { 185 if (auto handler = getActionHandle(session)) 186 { 187 return handler->stat(session, meta); 188 } 189 return false; 190 } 191 192 bool BlobManager::commit(uint16_t session, const std::vector<uint8_t>& data) 193 { 194 if (auto handler = getActionHandle(session)) 195 { 196 return handler->commit(session, data); 197 } 198 return false; 199 } 200 201 bool BlobManager::close(uint16_t session) 202 { 203 if (auto handler = getActionHandle(session)) 204 { 205 if (!handler->close(session)) 206 { 207 return false; 208 } 209 sessions.erase(session); 210 decrementOpen(getPath(session)); 211 return true; 212 } 213 return false; 214 } 215 216 std::vector<uint8_t> BlobManager::read(uint16_t session, uint32_t offset, 217 uint32_t requestedSize) 218 { 219 /* TODO: Currently, configure_ac isn't finding libuserlayer, w.r.t the 220 * symbols I need. 221 */ 222 223 /** The channel to use for now. 224 * TODO: We will receive this information through the IPMI message call. 225 */ 226 // const int ipmiChannel = ipmi::currentChNum; 227 /** This information is transport specific. 228 * TODO: We need a way to know this dynamically. 229 * on BT, 4 bytes of header, and 1 reply code. 230 */ 231 // uint32_t maxTransportSize = ipmi::getChannelMaxTransferSize(ipmiChannel); 232 233 if (auto handler = getActionHandle(session, OpenFlags::read)) 234 { 235 return handler->read(session, offset, 236 std::min(maximumReadSize, requestedSize)); 237 } 238 return {}; 239 } 240 241 bool BlobManager::write(uint16_t session, uint32_t offset, 242 const std::vector<uint8_t>& data) 243 { 244 if (auto handler = getActionHandle(session, OpenFlags::write)) 245 { 246 return handler->write(session, offset, data); 247 } 248 return {}; 249 } 250 251 bool BlobManager::deleteBlob(const std::string& path) 252 { 253 GenericBlobInterface* handler = getHandler(path); 254 255 /* No handler found. */ 256 if (!handler) 257 { 258 return false; 259 } 260 261 /* Check if the file has any open handles. */ 262 if (getOpen(path) > 0) 263 { 264 return false; 265 } 266 267 /* Try deleting it. */ 268 return handler->deleteBlob(path); 269 } 270 271 bool BlobManager::writeMeta(uint16_t session, uint32_t offset, 272 const std::vector<uint8_t>& data) 273 { 274 if (auto handler = getActionHandle(session)) 275 { 276 return handler->writeMeta(session, offset, data); 277 } 278 return false; 279 } 280 281 bool BlobManager::getSession(uint16_t* sess) 282 { 283 uint16_t tries = 0; 284 285 if (!sess) 286 { 287 return false; 288 } 289 290 /* This is not meant to fail as you have 64KiB values available. */ 291 292 /* TODO(venture): We could just count the keys in the session map to know 293 * if it's full. 294 */ 295 do 296 { 297 uint16_t lsess = next++; 298 if (!sessions.count(lsess)) 299 { 300 /* value not in use, return it. */ 301 (*sess) = lsess; 302 return true; 303 } 304 } while (++tries < 0xffff); 305 306 return false; 307 } 308 309 static std::unique_ptr<BlobManager> manager; 310 311 ManagerInterface* getBlobManager() 312 { 313 if (manager == nullptr) 314 { 315 manager = std::make_unique<BlobManager>(); 316 } 317 318 return manager.get(); 319 } 320 321 } // namespace blobs 322