blob: 525ec21e368b78e53a19801a646f09c2bd554ea5 [file] [log] [blame]
Kun Yi64dc05c2018-12-19 13:19:03 -08001#include "binarystore.hpp"
2
Kun Yi97be3af2019-03-05 22:43:41 -08003#include "sys_file.hpp"
4
William A. Kennington III7e145862024-02-01 15:56:33 -08005#include <pb_decode.h>
6#include <pb_encode.h>
Kun Yi97be3af2019-03-05 22:43:41 -08007#include <sys/types.h>
Kun Yid2d8cb62019-01-10 15:06:12 -08008#include <unistd.h>
9
Kun Yi6baa7132019-01-08 21:21:02 -080010#include <algorithm>
11#include <blobs-ipmid/blobs.hpp>
Kun Yi70059172019-02-22 16:31:42 -080012#include <boost/endian/arithmetic.hpp>
Kun Yid2d8cb62019-01-10 15:06:12 -080013#include <cstdint>
Maksym Sloykoeb274112021-10-27 23:48:32 +000014#include <ipmid/handler.hpp>
William A. Kennington III7e145862024-02-01 15:56:33 -080015#include <map>
Kun Yid2d8cb62019-01-10 15:06:12 -080016#include <memory>
Willy Tu67391d52021-12-07 19:53:49 -080017#include <optional>
Kun Yi8bcf79d2019-01-16 15:17:57 -080018#include <phosphor-logging/elog.hpp>
William A. Kennington III7e145862024-02-01 15:56:33 -080019#include <stdplus/str/cat.hpp>
Kun Yid2d8cb62019-01-10 15:06:12 -080020#include <string>
21#include <vector>
22
William A. Kennington III7e145862024-02-01 15:56:33 -080023#include "binaryblob.pb.n.h"
Kun Yid2d8cb62019-01-10 15:06:12 -080024
25using std::size_t;
26using std::uint16_t;
27using std::uint32_t;
28using std::uint64_t;
29using std::uint8_t;
Kun Yi6baa7132019-01-08 21:21:02 -080030
Kun Yi64dc05c2018-12-19 13:19:03 -080031namespace binstore
32{
33
Kun Yi8bcf79d2019-01-16 15:17:57 -080034using namespace phosphor::logging;
35
Willy Tu7f107802023-11-06 23:05:25 -080036std::unique_ptr<BinaryStoreInterface> BinaryStore::createFromConfig(
37 const std::string& baseBlobId, std::unique_ptr<SysFile> file,
38 std::optional<uint32_t> maxSize, std::optional<std::string> aliasBlobBaseId)
Kun Yi64dc05c2018-12-19 13:19:03 -080039{
Kun Yi2765b642019-01-16 11:11:24 -080040 if (baseBlobId.empty() || !file)
41 {
Kun Yi8bcf79d2019-01-16 15:17:57 -080042 log<level::ERR>("Unable to create binarystore from invalid config",
43 entry("BASE_ID=%s", baseBlobId.c_str()));
Kun Yi2765b642019-01-16 11:11:24 -080044 return nullptr;
45 }
46
Willy Tu67391d52021-12-07 19:53:49 -080047 auto store =
48 std::make_unique<BinaryStore>(baseBlobId, std::move(file), maxSize);
Kun Yi2765b642019-01-16 11:11:24 -080049
Willy Tu7f107802023-11-06 23:05:25 -080050 if (!store->loadSerializedData(aliasBlobBaseId))
Kun Yi8ca234e2019-03-04 10:14:45 -080051 {
52 return nullptr;
53 }
54
Willy Tu351a5d02021-12-07 19:48:40 -080055 return store;
Kun Yi64dc05c2018-12-19 13:19:03 -080056}
57
Maksym Sloykoeb274112021-10-27 23:48:32 +000058std::unique_ptr<BinaryStoreInterface>
Willy Tu67391d52021-12-07 19:53:49 -080059 BinaryStore::createFromFile(std::unique_ptr<SysFile> file, bool readOnly,
60 std::optional<uint32_t> maxSize)
Maksym Sloykoeb274112021-10-27 23:48:32 +000061{
62 if (!file)
63 {
64 log<level::ERR>("Unable to create binarystore from invalid file");
65 return nullptr;
66 }
67
Willy Tu67391d52021-12-07 19:53:49 -080068 auto store =
69 std::make_unique<BinaryStore>(std::move(file), readOnly, maxSize);
Maksym Sloykoeb274112021-10-27 23:48:32 +000070
71 if (!store->loadSerializedData())
72 {
73 return nullptr;
74 }
75
Willy Tu351a5d02021-12-07 19:48:40 -080076 return store;
Maksym Sloykoeb274112021-10-27 23:48:32 +000077}
78
William A. Kennington III7e145862024-02-01 15:56:33 -080079template <typename S>
80static constexpr auto pbDecodeStr = [](pb_istream_t* stream,
81 const pb_field_iter_t*,
82 void** arg) noexcept {
83 static_assert(sizeof(*std::declval<S>().data()) == sizeof(pb_byte_t));
84 auto& s = *reinterpret_cast<S*>(*arg);
85 s.resize(stream->bytes_left);
86 return pb_read(stream, reinterpret_cast<pb_byte_t*>(s.data()), s.size());
87};
88
89template <typename T>
90static pb_callback_t pbStrDecoder(T& t) noexcept
91{
92 return {{.decode = pbDecodeStr<T>}, &t};
93}
94
95template <typename S>
96static constexpr auto pbEncodeStr = [](pb_ostream_t* stream,
97 const pb_field_iter_t* field,
98 void* const* arg) noexcept {
99 static_assert(sizeof(*std::declval<S>().data()) == sizeof(pb_byte_t));
100 const auto& s = *reinterpret_cast<const S*>(*arg);
101 return pb_encode_tag_for_field(stream, field) &&
102 pb_encode_string(
103 stream, reinterpret_cast<const pb_byte_t*>(s.data()), s.size());
104};
105
106template <typename T>
107static pb_callback_t pbStrEncoder(const T& t) noexcept
108{
109 return {{.encode = pbEncodeStr<T>}, const_cast<T*>(&t)};
110}
111
Willy Tu7f107802023-11-06 23:05:25 -0800112bool BinaryStore::loadSerializedData(std::optional<std::string> aliasBlobBaseId)
Kun Yi97be3af2019-03-05 22:43:41 -0800113{
114 /* Load blob from sysfile if we know it might not match what we have.
115 * Note it will overwrite existing unsaved data per design. */
Kun Yie535a732019-04-03 19:03:25 -0700116 if (commitState_ == CommitState::Clean ||
117 commitState_ == CommitState::Uninitialized)
Kun Yi97be3af2019-03-05 22:43:41 -0800118 {
119 return true;
120 }
121
122 log<level::NOTICE>("Try loading blob from persistent data",
123 entry("BASE_ID=%s", baseBlobId_.c_str()));
William A. Kennington III7e145862024-02-01 15:56:33 -0800124 std::string protoBlobId;
125 static constexpr auto blobcb = [](pb_istream_t* stream,
126 const pb_field_iter_t*,
127 void** arg) noexcept {
128 std::string id;
129 std::vector<std::uint8_t> data;
130 binstore_binaryblobproto_BinaryBlob msg = {
131 .blob_id = pbStrDecoder(id),
132 .data = pbStrDecoder(data),
133 };
134 if (!pb_decode(stream, binstore_binaryblobproto_BinaryBlob_fields,
135 &msg))
136 {
137 return false;
138 }
139 reinterpret_cast<decltype(std::declval<BinaryStore>().blobs_)*>(*arg)
140 ->emplace(id, data);
141 return true;
142 };
143
Kun Yi97be3af2019-03-05 22:43:41 -0800144 try
145 {
146 /* Parse length-prefixed format to protobuf */
147 boost::endian::little_uint64_t size = 0;
148 file_->readToBuf(0, sizeof(size), reinterpret_cast<char*>(&size));
William A. Kennington III7e145862024-02-01 15:56:33 -0800149 auto proto = file_->readAsStr(sizeof(size), size);
Kun Yi97be3af2019-03-05 22:43:41 -0800150
William A. Kennington III7e145862024-02-01 15:56:33 -0800151 auto ist = pb_istream_from_buffer(
152 reinterpret_cast<const pb_byte_t*>(proto.data()), proto.size());
153 binstore_binaryblobproto_BinaryBlobBase msg = {
154 .blob_base_id = pbStrDecoder(protoBlobId),
155 .blobs = {{.decode = blobcb}, &blobs_},
156 };
157 blobs_.clear(); // Purge old contents before new append during decode
158 if (!pb_decode(&ist, binstore_binaryblobproto_BinaryBlobBase_fields,
159 &msg))
Kun Yi97be3af2019-03-05 22:43:41 -0800160 {
161 /* Fail to parse the data, which might mean no preexsiting blobs
162 * and is a valid case to handle. Simply init an empty binstore. */
Kun Yie535a732019-04-03 19:03:25 -0700163 commitState_ = CommitState::Uninitialized;
Kun Yi97be3af2019-03-05 22:43:41 -0800164 }
165 }
Kun Yic83d2fa2019-04-03 18:40:19 -0700166 catch (const std::system_error& e)
Kun Yi97be3af2019-03-05 22:43:41 -0800167 {
168 /* Read causes unexpected system-level failure */
169 log<level::ERR>("Reading from sysfile failed",
170 entry("ERROR=%s", e.what()));
171 return false;
172 }
Kun Yic83d2fa2019-04-03 18:40:19 -0700173 catch (const std::exception& e)
174 {
Kun Yie535a732019-04-03 19:03:25 -0700175 /* Non system error originates from junk value in 'size' */
176 commitState_ = CommitState::Uninitialized;
177 }
178
179 if (commitState_ == CommitState::Uninitialized)
180 {
181 log<level::WARNING>("Fail to parse. There might be no persisted blobs",
182 entry("BASE_ID=%s", baseBlobId_.c_str()));
Kun Yic83d2fa2019-04-03 18:40:19 -0700183 return true;
184 }
Kun Yi97be3af2019-03-05 22:43:41 -0800185
William A. Kennington III7e145862024-02-01 15:56:33 -0800186 if (baseBlobId_.empty() && !protoBlobId.empty())
187 {
188 baseBlobId_ = std::move(protoBlobId);
189 }
190 else if (protoBlobId == aliasBlobBaseId)
Willy Tu7f107802023-11-06 23:05:25 -0800191 {
192 log<level::WARNING>("Alias blob id, rename blob id...",
William A. Kennington III7e145862024-02-01 15:56:33 -0800193 entry("LOADED=%s", protoBlobId.c_str()),
Willy Tu7f107802023-11-06 23:05:25 -0800194 entry("RENAMED=%s", baseBlobId_.c_str()));
195 std::string tmpBlobId = baseBlobId_;
William A. Kennington III7e145862024-02-01 15:56:33 -0800196 baseBlobId_ = *aliasBlobBaseId;
Willy Tu7f107802023-11-06 23:05:25 -0800197 return setBaseBlobId(tmpBlobId);
198 }
William A. Kennington III7e145862024-02-01 15:56:33 -0800199 else if (protoBlobId != baseBlobId_ && !readOnly_)
Kun Yi8ca234e2019-03-04 10:14:45 -0800200 {
201 /* Uh oh, stale data loaded. Clean it and commit. */
202 // TODO: it might be safer to add an option in config to error out
203 // instead of to overwrite.
204 log<level::ERR>("Stale blob data, resetting internals...",
William A. Kennington III7e145862024-02-01 15:56:33 -0800205 entry("LOADED=%s", protoBlobId.c_str()),
Kun Yi8ca234e2019-03-04 10:14:45 -0800206 entry("EXPECTED=%s", baseBlobId_.c_str()));
William A. Kennington III7e145862024-02-01 15:56:33 -0800207 blobs_.clear();
Kun Yi8ca234e2019-03-04 10:14:45 -0800208 return this->commit();
209 }
210
Kun Yi97be3af2019-03-05 22:43:41 -0800211 return true;
212}
213
Kun Yi64dc05c2018-12-19 13:19:03 -0800214std::string BinaryStore::getBaseBlobId() const
215{
William A. Kennington III7e145862024-02-01 15:56:33 -0800216 return baseBlobId_;
Kun Yi64dc05c2018-12-19 13:19:03 -0800217}
218
Willy Tu7f107802023-11-06 23:05:25 -0800219bool BinaryStore::setBaseBlobId(const std::string& baseBlobId)
220{
William A. Kennington III7e145862024-02-01 15:56:33 -0800221 for (auto it = blobs_.begin(); it != blobs_.end();)
Willy Tu7f107802023-11-06 23:05:25 -0800222 {
William A. Kennington III7e145862024-02-01 15:56:33 -0800223 auto curr = it++;
224 if (curr->first.starts_with(baseBlobId_))
Willy Tu7f107802023-11-06 23:05:25 -0800225 {
William A. Kennington III7e145862024-02-01 15:56:33 -0800226 auto nh = blobs_.extract(curr);
227 nh.key() = stdplus::strCat(
228 baseBlobId,
229 std::string_view(curr->first).substr(baseBlobId_.size()));
230 blobs_.insert(std::move(nh));
Willy Tu7f107802023-11-06 23:05:25 -0800231 }
232 }
William A. Kennington III7e145862024-02-01 15:56:33 -0800233 baseBlobId_ = baseBlobId;
Willy Tu7f107802023-11-06 23:05:25 -0800234 return this->commit();
235}
236
Kun Yi64dc05c2018-12-19 13:19:03 -0800237std::vector<std::string> BinaryStore::getBlobIds() const
238{
239 std::vector<std::string> result;
William A. Kennington III7e145862024-02-01 15:56:33 -0800240 result.reserve(blobs_.size() + 1);
Willy Tufdebaa32022-02-08 16:34:20 -0800241 result.emplace_back(getBaseBlobId());
William A. Kennington III7e145862024-02-01 15:56:33 -0800242 for (const auto& kv : blobs_)
243 {
244 result.emplace_back(kv.first);
245 }
Kun Yi64dc05c2018-12-19 13:19:03 -0800246 return result;
247}
248
249bool BinaryStore::openOrCreateBlob(const std::string& blobId, uint16_t flags)
250{
Kun Yi6baa7132019-01-08 21:21:02 -0800251 if (!(flags & blobs::OpenFlags::read))
252 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800253 log<level::ERR>("OpenFlags::read not specified when opening",
254 entry("BLOB_ID=%s", blobId.c_str()));
Kun Yi6baa7132019-01-08 21:21:02 -0800255 return false;
256 }
257
William A. Kennington III7e145862024-02-01 15:56:33 -0800258 if (!currentBlob_.empty())
Kun Yi6baa7132019-01-08 21:21:02 -0800259 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800260 log<level::ERR>("Already handling a different blob",
William A. Kennington III7e145862024-02-01 15:56:33 -0800261 entry("EXPECTED=%s", currentBlob_.c_str()),
Kun Yi8bcf79d2019-01-16 15:17:57 -0800262 entry("RECEIVED=%s", blobId.c_str()));
Kun Yi6baa7132019-01-08 21:21:02 -0800263 return false;
264 }
265
Maksym Sloykoeb274112021-10-27 23:48:32 +0000266 if (readOnly_ && (flags & blobs::OpenFlags::write))
267 {
268 log<level::ERR>("Can't open the blob for writing: read-only store",
269 entry("BLOB_ID=%s", blobId.c_str()));
270 return false;
271 }
272
Kun Yi6baa7132019-01-08 21:21:02 -0800273 writable_ = flags & blobs::OpenFlags::write;
274
Kun Yi97be3af2019-03-05 22:43:41 -0800275 /* If there are uncommitted data, discard them. */
276 if (!this->loadSerializedData())
Kun Yid297c9f2019-01-09 13:52:30 -0800277 {
Kun Yi97be3af2019-03-05 22:43:41 -0800278 return false;
Kun Yid297c9f2019-01-09 13:52:30 -0800279 }
280
Kun Yi6baa7132019-01-08 21:21:02 -0800281 /* Iterate and find if there is an existing blob with this id.
282 * blobsPtr points to a BinaryBlob container with STL-like semantics*/
William A. Kennington III7e145862024-02-01 15:56:33 -0800283 if (blobs_.find(blobId) != blobs_.end())
Kun Yi6baa7132019-01-08 21:21:02 -0800284 {
William A. Kennington III7e145862024-02-01 15:56:33 -0800285 currentBlob_ = blobId;
Kun Yi6baa7132019-01-08 21:21:02 -0800286 return true;
287 }
288
289 /* Otherwise, create the blob and append it */
Maksym Sloykoeb274112021-10-27 23:48:32 +0000290 if (readOnly_)
291 {
292 return false;
293 }
Kun Yi6baa7132019-01-08 21:21:02 -0800294
William A. Kennington III7e145862024-02-01 15:56:33 -0800295 blobs_.emplace(blobId, std::vector<std::uint8_t>{});
296 currentBlob_ = blobId;
297 commitState_ = CommitState::Dirty;
298 log<level::NOTICE>("Created new blob", entry("BLOB_ID=%s", blobId.c_str()));
Kun Yi6baa7132019-01-08 21:21:02 -0800299 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800300}
301
Willy Tu351a5d02021-12-07 19:48:40 -0800302bool BinaryStore::deleteBlob(const std::string&)
Kun Yi64dc05c2018-12-19 13:19:03 -0800303{
304 return false;
305}
306
307std::vector<uint8_t> BinaryStore::read(uint32_t offset, uint32_t requestedSize)
308{
William A. Kennington III7e145862024-02-01 15:56:33 -0800309 if (currentBlob_.empty())
Kun Yi6967b772019-02-22 13:48:12 -0800310 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800311 log<level::ERR>("No open blob to read");
William A. Kennington III7e145862024-02-01 15:56:33 -0800312 return {};
Kun Yi6967b772019-02-22 13:48:12 -0800313 }
314
William A. Kennington III7e145862024-02-01 15:56:33 -0800315 const auto& data = blobs_.find(currentBlob_)->second;
Kun Yi6967b772019-02-22 13:48:12 -0800316
317 /* If it is out of bound, return empty vector */
William A. Kennington III7e145862024-02-01 15:56:33 -0800318 if (offset >= data.size())
Kun Yi6967b772019-02-22 13:48:12 -0800319 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800320 log<level::ERR>("Read offset is beyond data size",
William A. Kennington III7e145862024-02-01 15:56:33 -0800321 entry("MAX_SIZE=0x%x", data.size()),
Kun Yi8bcf79d2019-01-16 15:17:57 -0800322 entry("RECEIVED_OFFSET=0x%x", offset));
William A. Kennington III7e145862024-02-01 15:56:33 -0800323 return {};
Kun Yi6967b772019-02-22 13:48:12 -0800324 }
325
William A. Kennington III7e145862024-02-01 15:56:33 -0800326 auto s = data.begin() + offset;
327 return {s, s + std::min<size_t>(requestedSize, data.size() - offset)};
Kun Yi64dc05c2018-12-19 13:19:03 -0800328}
329
Maksym Sloykoeb274112021-10-27 23:48:32 +0000330std::vector<uint8_t> BinaryStore::readBlob(const std::string& blobId) const
331{
William A. Kennington III7e145862024-02-01 15:56:33 -0800332 const auto blobIt = blobs_.find(blobId);
333 if (blobIt == blobs_.end())
Maksym Sloykoeb274112021-10-27 23:48:32 +0000334 {
335 throw ipmi::HandlerCompletion(ipmi::ccUnspecifiedError);
336 }
William A. Kennington III7e145862024-02-01 15:56:33 -0800337 return blobIt->second;
338}
Maksym Sloykoeb274112021-10-27 23:48:32 +0000339
William A. Kennington III7e145862024-02-01 15:56:33 -0800340static binstore_binaryblobproto_BinaryBlobBase makeEncoder(
341 const std::string& base,
342 const std::map<std::string, std::vector<std::uint8_t>>& blobs) noexcept
343{
344 using Blobs = std::decay_t<decltype(blobs)>;
345 static constexpr auto blobcb = [](pb_ostream_t* stream,
346 const pb_field_iter_t* field,
347 void* const* arg) noexcept {
348 const auto& blobs = *reinterpret_cast<const Blobs*>(*arg);
349 for (const auto& [id, data] : blobs)
350 {
351 binstore_binaryblobproto_BinaryBlob msg = {
352 .blob_id = pbStrEncoder(id),
353 .data = pbStrEncoder(data),
354 };
355 if (!pb_encode_tag_for_field(stream, field) ||
356 !pb_encode_submessage(
357 stream, binstore_binaryblobproto_BinaryBlob_fields, &msg))
358 {
359 return false;
360 }
361 }
362 return true;
363 };
364 return {
365 .blob_base_id = pbStrEncoder(base),
366 .blobs = {{.encode = blobcb},
367 const_cast<void*>(reinterpret_cast<const void*>(&blobs))},
368 };
369}
Maksym Sloykoeb274112021-10-27 23:48:32 +0000370
William A. Kennington III7e145862024-02-01 15:56:33 -0800371static std::size_t
372 payloadCalcSize(const binstore_binaryblobproto_BinaryBlobBase& msg)
373{
374 pb_ostream_t nost = {};
375 if (!pb_encode(&nost, binstore_binaryblobproto_BinaryBlobBase_fields, &msg))
376 {
377 throw std::runtime_error(
378 std::format("Calculating msg size: {}", PB_GET_ERROR(&nost)));
379 }
380 // Proto is prepended with the size of the proto
381 return nost.bytes_written + sizeof(boost::endian::little_uint64_t);
Maksym Sloykoeb274112021-10-27 23:48:32 +0000382}
383
Kun Yi64dc05c2018-12-19 13:19:03 -0800384bool BinaryStore::write(uint32_t offset, const std::vector<uint8_t>& data)
385{
William A. Kennington III7e145862024-02-01 15:56:33 -0800386 if (currentBlob_.empty())
Kun Yi6967b772019-02-22 13:48:12 -0800387 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800388 log<level::ERR>("No open blob to write");
Kun Yi6967b772019-02-22 13:48:12 -0800389 return false;
390 }
391
392 if (!writable_)
393 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800394 log<level::ERR>("Open blob is not writable");
Kun Yi6967b772019-02-22 13:48:12 -0800395 return false;
396 }
397
William A. Kennington III7e145862024-02-01 15:56:33 -0800398 auto& bdata = blobs_.find(currentBlob_)->second;
399 if (offset > bdata.size())
Kun Yi6967b772019-02-22 13:48:12 -0800400 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800401 log<level::ERR>("Write would leave a gap with undefined data. Return.");
Kun Yi6967b772019-02-22 13:48:12 -0800402 return false;
403 }
404
William A. Kennington III7e145862024-02-01 15:56:33 -0800405 std::size_t oldsize = bdata.size(), reqSize = offset + data.size();
406 if (reqSize > bdata.size())
407 {
408 bdata.resize(reqSize);
409 }
Willy Tu67391d52021-12-07 19:53:49 -0800410
William A. Kennington III7e145862024-02-01 15:56:33 -0800411 if (payloadCalcSize(makeEncoder(baseBlobId_, blobs_)) >
412 maxSize.value_or(
413 std::numeric_limits<std::decay_t<decltype(*maxSize)>>::max()))
Willy Tu67391d52021-12-07 19:53:49 -0800414 {
415 log<level::ERR>("Write data would make the total size exceed the max "
416 "size allowed. Return.");
William A. Kennington III7e145862024-02-01 15:56:33 -0800417 bdata.resize(oldsize);
Willy Tu67391d52021-12-07 19:53:49 -0800418 return false;
419 }
420
Kun Yi1a25e0d2020-05-11 12:28:53 -0700421 commitState_ = CommitState::Dirty;
William A. Kennington III7e145862024-02-01 15:56:33 -0800422 std::copy(data.begin(), data.end(), bdata.data() + offset);
Kun Yi6967b772019-02-22 13:48:12 -0800423 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800424}
425
426bool BinaryStore::commit()
427{
Maksym Sloykoeb274112021-10-27 23:48:32 +0000428 if (readOnly_)
429 {
430 log<level::ERR>("ReadOnly blob, not committing");
431 return false;
432 }
433
Kun Yi70059172019-02-22 16:31:42 -0800434 /* Store as little endian to be platform agnostic. Consistent with read. */
William A. Kennington III7e145862024-02-01 15:56:33 -0800435 auto msg = makeEncoder(baseBlobId_, blobs_);
436 auto outSize = payloadCalcSize(msg);
437 if (outSize >
438 maxSize.value_or(
439 std::numeric_limits<std::decay_t<decltype(*maxSize)>>::max()))
Willy Tu67391d52021-12-07 19:53:49 -0800440 {
Willy Tu91633852022-02-18 08:55:43 -0800441 log<level::ERR>("Commit Data exceeded maximum allowed size");
Willy Tu67391d52021-12-07 19:53:49 -0800442 return false;
443 }
William A. Kennington III7e145862024-02-01 15:56:33 -0800444 std::string buf(outSize, '\0');
445 auto& size = *reinterpret_cast<boost::endian::little_uint64_t*>(buf.data());
446 auto ost = pb_ostream_from_buffer(reinterpret_cast<pb_byte_t*>(buf.data()) +
447 sizeof(size),
448 buf.size() - sizeof(size));
449 pb_encode(&ost, binstore_binaryblobproto_BinaryBlobBase_fields, &msg);
450 size = ost.bytes_written;
Kun Yid297c9f2019-01-09 13:52:30 -0800451 try
452 {
William A. Kennington III7e145862024-02-01 15:56:33 -0800453 file_->writeStr(buf, 0);
Kun Yid297c9f2019-01-09 13:52:30 -0800454 }
455 catch (const std::exception& e)
456 {
Kun Yid297c9f2019-01-09 13:52:30 -0800457 commitState_ = CommitState::CommitError;
Kun Yi8bcf79d2019-01-16 15:17:57 -0800458 log<level::ERR>("Writing to sysfile failed",
459 entry("ERROR=%s", e.what()));
Kun Yid297c9f2019-01-09 13:52:30 -0800460 return false;
461 };
462
463 commitState_ = CommitState::Clean;
464 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800465}
466
467bool BinaryStore::close()
468{
William A. Kennington III7e145862024-02-01 15:56:33 -0800469 currentBlob_.clear();
Kun Yi6baa7132019-01-08 21:21:02 -0800470 writable_ = false;
Kun Yid297c9f2019-01-09 13:52:30 -0800471 commitState_ = CommitState::Dirty;
Kun Yi6baa7132019-01-08 21:21:02 -0800472 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800473}
474
Kun Yi1a25e0d2020-05-11 12:28:53 -0700475/*
476 * Sets |meta| with size and state of the blob. Returns |blobState| with
477 * standard definition from phosphor-ipmi-blobs header blob.hpp, plus OEM
478 * flag bits BinaryStore::CommitState.
479
480enum StateFlags
Kun Yi64dc05c2018-12-19 13:19:03 -0800481{
Kun Yi1a25e0d2020-05-11 12:28:53 -0700482 open_read = (1 << 0),
483 open_write = (1 << 1),
484 committing = (1 << 2),
485 committed = (1 << 3),
486 commit_error = (1 << 4),
487};
488
489enum CommitState
490{
491 Dirty = (1 << 8), // In-memory data might not match persisted data
492 Clean = (1 << 9), // In-memory data matches persisted data
493 Uninitialized = (1 << 10), // Cannot find persisted data
494 CommitError = (1 << 11) // Error happened during committing
495};
496
497*/
498bool BinaryStore::stat(blobs::BlobMeta* meta)
499{
500 uint16_t blobState = blobs::StateFlags::open_read;
501 if (writable_)
502 {
503 blobState |= blobs::StateFlags::open_write;
504 }
505
506 if (commitState_ == CommitState::Clean)
507 {
508 blobState |= blobs::StateFlags::committed;
509 }
510 else if (commitState_ == CommitState::CommitError)
511 {
512 blobState |= blobs::StateFlags::commit_error;
513 }
514 blobState |= commitState_;
515
William A. Kennington III7e145862024-02-01 15:56:33 -0800516 if (!currentBlob_.empty())
Kun Yi1a25e0d2020-05-11 12:28:53 -0700517 {
William A. Kennington III7e145862024-02-01 15:56:33 -0800518 meta->size = blobs_.find(currentBlob_)->second.size();
Kun Yi1a25e0d2020-05-11 12:28:53 -0700519 }
520 else
521 {
522 meta->size = 0;
523 }
524 meta->blobState = blobState;
525
526 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800527}
528
529} // namespace binstore