blob: 65e7721d8fd6239fde3a4698a8d495ca310528e0 [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
William A. Kennington III7e145862024-02-01 15:56:33 -0800122 std::string protoBlobId;
123 static constexpr auto blobcb = [](pb_istream_t* stream,
124 const pb_field_iter_t*,
125 void** arg) noexcept {
126 std::string id;
127 std::vector<std::uint8_t> data;
128 binstore_binaryblobproto_BinaryBlob msg = {
129 .blob_id = pbStrDecoder(id),
130 .data = pbStrDecoder(data),
131 };
132 if (!pb_decode(stream, binstore_binaryblobproto_BinaryBlob_fields,
133 &msg))
134 {
135 return false;
136 }
137 reinterpret_cast<decltype(std::declval<BinaryStore>().blobs_)*>(*arg)
138 ->emplace(id, data);
139 return true;
140 };
141
Kun Yi97be3af2019-03-05 22:43:41 -0800142 try
143 {
144 /* Parse length-prefixed format to protobuf */
145 boost::endian::little_uint64_t size = 0;
146 file_->readToBuf(0, sizeof(size), reinterpret_cast<char*>(&size));
William A. Kennington III7e145862024-02-01 15:56:33 -0800147 auto proto = file_->readAsStr(sizeof(size), size);
Kun Yi97be3af2019-03-05 22:43:41 -0800148
William A. Kennington III7e145862024-02-01 15:56:33 -0800149 auto ist = pb_istream_from_buffer(
150 reinterpret_cast<const pb_byte_t*>(proto.data()), proto.size());
151 binstore_binaryblobproto_BinaryBlobBase msg = {
152 .blob_base_id = pbStrDecoder(protoBlobId),
153 .blobs = {{.decode = blobcb}, &blobs_},
154 };
155 blobs_.clear(); // Purge old contents before new append during decode
156 if (!pb_decode(&ist, binstore_binaryblobproto_BinaryBlobBase_fields,
157 &msg))
Kun Yi97be3af2019-03-05 22:43:41 -0800158 {
159 /* Fail to parse the data, which might mean no preexsiting blobs
160 * and is a valid case to handle. Simply init an empty binstore. */
Kun Yie535a732019-04-03 19:03:25 -0700161 commitState_ = CommitState::Uninitialized;
Kun Yi97be3af2019-03-05 22:43:41 -0800162 }
163 }
Kun Yic83d2fa2019-04-03 18:40:19 -0700164 catch (const std::system_error& e)
Kun Yi97be3af2019-03-05 22:43:41 -0800165 {
166 /* Read causes unexpected system-level failure */
167 log<level::ERR>("Reading from sysfile failed",
168 entry("ERROR=%s", e.what()));
169 return false;
170 }
Kun Yic83d2fa2019-04-03 18:40:19 -0700171 catch (const std::exception& e)
172 {
Kun Yie535a732019-04-03 19:03:25 -0700173 /* Non system error originates from junk value in 'size' */
174 commitState_ = CommitState::Uninitialized;
175 }
176
177 if (commitState_ == CommitState::Uninitialized)
178 {
179 log<level::WARNING>("Fail to parse. There might be no persisted blobs",
180 entry("BASE_ID=%s", baseBlobId_.c_str()));
Kun Yic83d2fa2019-04-03 18:40:19 -0700181 return true;
182 }
Kun Yi97be3af2019-03-05 22:43:41 -0800183
William A. Kennington III7e145862024-02-01 15:56:33 -0800184 if (baseBlobId_.empty() && !protoBlobId.empty())
185 {
186 baseBlobId_ = std::move(protoBlobId);
187 }
188 else if (protoBlobId == aliasBlobBaseId)
Willy Tu7f107802023-11-06 23:05:25 -0800189 {
190 log<level::WARNING>("Alias blob id, rename blob id...",
William A. Kennington III7e145862024-02-01 15:56:33 -0800191 entry("LOADED=%s", protoBlobId.c_str()),
Willy Tu7f107802023-11-06 23:05:25 -0800192 entry("RENAMED=%s", baseBlobId_.c_str()));
193 std::string tmpBlobId = baseBlobId_;
William A. Kennington III7e145862024-02-01 15:56:33 -0800194 baseBlobId_ = *aliasBlobBaseId;
Willy Tu7f107802023-11-06 23:05:25 -0800195 return setBaseBlobId(tmpBlobId);
196 }
William A. Kennington III7e145862024-02-01 15:56:33 -0800197 else if (protoBlobId != baseBlobId_ && !readOnly_)
Kun Yi8ca234e2019-03-04 10:14:45 -0800198 {
199 /* Uh oh, stale data loaded. Clean it and commit. */
200 // TODO: it might be safer to add an option in config to error out
201 // instead of to overwrite.
202 log<level::ERR>("Stale blob data, resetting internals...",
William A. Kennington III7e145862024-02-01 15:56:33 -0800203 entry("LOADED=%s", protoBlobId.c_str()),
Kun Yi8ca234e2019-03-04 10:14:45 -0800204 entry("EXPECTED=%s", baseBlobId_.c_str()));
William A. Kennington III7e145862024-02-01 15:56:33 -0800205 blobs_.clear();
Kun Yi8ca234e2019-03-04 10:14:45 -0800206 return this->commit();
207 }
208
Kun Yi97be3af2019-03-05 22:43:41 -0800209 return true;
210}
211
Kun Yi64dc05c2018-12-19 13:19:03 -0800212std::string BinaryStore::getBaseBlobId() const
213{
William A. Kennington III7e145862024-02-01 15:56:33 -0800214 return baseBlobId_;
Kun Yi64dc05c2018-12-19 13:19:03 -0800215}
216
Willy Tu7f107802023-11-06 23:05:25 -0800217bool BinaryStore::setBaseBlobId(const std::string& baseBlobId)
218{
William A. Kennington III7e145862024-02-01 15:56:33 -0800219 for (auto it = blobs_.begin(); it != blobs_.end();)
Willy Tu7f107802023-11-06 23:05:25 -0800220 {
William A. Kennington III7e145862024-02-01 15:56:33 -0800221 auto curr = it++;
222 if (curr->first.starts_with(baseBlobId_))
Willy Tu7f107802023-11-06 23:05:25 -0800223 {
William A. Kennington III7e145862024-02-01 15:56:33 -0800224 auto nh = blobs_.extract(curr);
225 nh.key() = stdplus::strCat(
226 baseBlobId,
227 std::string_view(curr->first).substr(baseBlobId_.size()));
228 blobs_.insert(std::move(nh));
Willy Tu7f107802023-11-06 23:05:25 -0800229 }
230 }
William A. Kennington III7e145862024-02-01 15:56:33 -0800231 baseBlobId_ = baseBlobId;
Willy Tu7f107802023-11-06 23:05:25 -0800232 return this->commit();
233}
234
Kun Yi64dc05c2018-12-19 13:19:03 -0800235std::vector<std::string> BinaryStore::getBlobIds() const
236{
237 std::vector<std::string> result;
William A. Kennington III7e145862024-02-01 15:56:33 -0800238 result.reserve(blobs_.size() + 1);
Willy Tufdebaa32022-02-08 16:34:20 -0800239 result.emplace_back(getBaseBlobId());
William A. Kennington III7e145862024-02-01 15:56:33 -0800240 for (const auto& kv : blobs_)
241 {
242 result.emplace_back(kv.first);
243 }
Kun Yi64dc05c2018-12-19 13:19:03 -0800244 return result;
245}
246
247bool BinaryStore::openOrCreateBlob(const std::string& blobId, uint16_t flags)
248{
Kun Yi6baa7132019-01-08 21:21:02 -0800249 if (!(flags & blobs::OpenFlags::read))
250 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800251 log<level::ERR>("OpenFlags::read not specified when opening",
252 entry("BLOB_ID=%s", blobId.c_str()));
Kun Yi6baa7132019-01-08 21:21:02 -0800253 return false;
254 }
255
William A. Kennington III7e145862024-02-01 15:56:33 -0800256 if (!currentBlob_.empty())
Kun Yi6baa7132019-01-08 21:21:02 -0800257 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800258 log<level::ERR>("Already handling a different blob",
William A. Kennington III7e145862024-02-01 15:56:33 -0800259 entry("EXPECTED=%s", currentBlob_.c_str()),
Kun Yi8bcf79d2019-01-16 15:17:57 -0800260 entry("RECEIVED=%s", blobId.c_str()));
Kun Yi6baa7132019-01-08 21:21:02 -0800261 return false;
262 }
263
Maksym Sloykoeb274112021-10-27 23:48:32 +0000264 if (readOnly_ && (flags & blobs::OpenFlags::write))
265 {
266 log<level::ERR>("Can't open the blob for writing: read-only store",
267 entry("BLOB_ID=%s", blobId.c_str()));
268 return false;
269 }
270
Kun Yi6baa7132019-01-08 21:21:02 -0800271 writable_ = flags & blobs::OpenFlags::write;
272
Kun Yi97be3af2019-03-05 22:43:41 -0800273 /* If there are uncommitted data, discard them. */
274 if (!this->loadSerializedData())
Kun Yid297c9f2019-01-09 13:52:30 -0800275 {
Kun Yi97be3af2019-03-05 22:43:41 -0800276 return false;
Kun Yid297c9f2019-01-09 13:52:30 -0800277 }
278
Kun Yi6baa7132019-01-08 21:21:02 -0800279 /* Iterate and find if there is an existing blob with this id.
280 * blobsPtr points to a BinaryBlob container with STL-like semantics*/
William A. Kennington III7e145862024-02-01 15:56:33 -0800281 if (blobs_.find(blobId) != blobs_.end())
Kun Yi6baa7132019-01-08 21:21:02 -0800282 {
William A. Kennington III7e145862024-02-01 15:56:33 -0800283 currentBlob_ = blobId;
Kun Yi6baa7132019-01-08 21:21:02 -0800284 return true;
285 }
286
287 /* Otherwise, create the blob and append it */
Maksym Sloykoeb274112021-10-27 23:48:32 +0000288 if (readOnly_)
289 {
290 return false;
291 }
Kun Yi6baa7132019-01-08 21:21:02 -0800292
William A. Kennington III7e145862024-02-01 15:56:33 -0800293 blobs_.emplace(blobId, std::vector<std::uint8_t>{});
294 currentBlob_ = blobId;
295 commitState_ = CommitState::Dirty;
Kun Yi6baa7132019-01-08 21:21:02 -0800296 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800297}
298
Willy Tu351a5d02021-12-07 19:48:40 -0800299bool BinaryStore::deleteBlob(const std::string&)
Kun Yi64dc05c2018-12-19 13:19:03 -0800300{
301 return false;
302}
303
304std::vector<uint8_t> BinaryStore::read(uint32_t offset, uint32_t requestedSize)
305{
William A. Kennington III7e145862024-02-01 15:56:33 -0800306 if (currentBlob_.empty())
Kun Yi6967b772019-02-22 13:48:12 -0800307 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800308 log<level::ERR>("No open blob to read");
William A. Kennington III7e145862024-02-01 15:56:33 -0800309 return {};
Kun Yi6967b772019-02-22 13:48:12 -0800310 }
311
William A. Kennington III7e145862024-02-01 15:56:33 -0800312 const auto& data = blobs_.find(currentBlob_)->second;
Kun Yi6967b772019-02-22 13:48:12 -0800313
314 /* If it is out of bound, return empty vector */
William A. Kennington III7e145862024-02-01 15:56:33 -0800315 if (offset >= data.size())
Kun Yi6967b772019-02-22 13:48:12 -0800316 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800317 log<level::ERR>("Read offset is beyond data size",
William A. Kennington III7e145862024-02-01 15:56:33 -0800318 entry("MAX_SIZE=0x%x", data.size()),
Kun Yi8bcf79d2019-01-16 15:17:57 -0800319 entry("RECEIVED_OFFSET=0x%x", offset));
William A. Kennington III7e145862024-02-01 15:56:33 -0800320 return {};
Kun Yi6967b772019-02-22 13:48:12 -0800321 }
322
William A. Kennington III7e145862024-02-01 15:56:33 -0800323 auto s = data.begin() + offset;
324 return {s, s + std::min<size_t>(requestedSize, data.size() - offset)};
Kun Yi64dc05c2018-12-19 13:19:03 -0800325}
326
Maksym Sloykoeb274112021-10-27 23:48:32 +0000327std::vector<uint8_t> BinaryStore::readBlob(const std::string& blobId) const
328{
William A. Kennington III7e145862024-02-01 15:56:33 -0800329 const auto blobIt = blobs_.find(blobId);
330 if (blobIt == blobs_.end())
Maksym Sloykoeb274112021-10-27 23:48:32 +0000331 {
332 throw ipmi::HandlerCompletion(ipmi::ccUnspecifiedError);
333 }
William A. Kennington III7e145862024-02-01 15:56:33 -0800334 return blobIt->second;
335}
Maksym Sloykoeb274112021-10-27 23:48:32 +0000336
William A. Kennington III7e145862024-02-01 15:56:33 -0800337static binstore_binaryblobproto_BinaryBlobBase makeEncoder(
338 const std::string& base,
339 const std::map<std::string, std::vector<std::uint8_t>>& blobs) noexcept
340{
341 using Blobs = std::decay_t<decltype(blobs)>;
342 static constexpr auto blobcb = [](pb_ostream_t* stream,
343 const pb_field_iter_t* field,
344 void* const* arg) noexcept {
345 const auto& blobs = *reinterpret_cast<const Blobs*>(*arg);
346 for (const auto& [id, data] : blobs)
347 {
348 binstore_binaryblobproto_BinaryBlob msg = {
349 .blob_id = pbStrEncoder(id),
350 .data = pbStrEncoder(data),
351 };
352 if (!pb_encode_tag_for_field(stream, field) ||
353 !pb_encode_submessage(
354 stream, binstore_binaryblobproto_BinaryBlob_fields, &msg))
355 {
356 return false;
357 }
358 }
359 return true;
360 };
361 return {
362 .blob_base_id = pbStrEncoder(base),
363 .blobs = {{.encode = blobcb},
364 const_cast<void*>(reinterpret_cast<const void*>(&blobs))},
365 };
366}
Maksym Sloykoeb274112021-10-27 23:48:32 +0000367
William A. Kennington III7e145862024-02-01 15:56:33 -0800368static std::size_t
369 payloadCalcSize(const binstore_binaryblobproto_BinaryBlobBase& msg)
370{
371 pb_ostream_t nost = {};
372 if (!pb_encode(&nost, binstore_binaryblobproto_BinaryBlobBase_fields, &msg))
373 {
374 throw std::runtime_error(
375 std::format("Calculating msg size: {}", PB_GET_ERROR(&nost)));
376 }
377 // Proto is prepended with the size of the proto
378 return nost.bytes_written + sizeof(boost::endian::little_uint64_t);
Maksym Sloykoeb274112021-10-27 23:48:32 +0000379}
380
Kun Yi64dc05c2018-12-19 13:19:03 -0800381bool BinaryStore::write(uint32_t offset, const std::vector<uint8_t>& data)
382{
William A. Kennington III7e145862024-02-01 15:56:33 -0800383 if (currentBlob_.empty())
Kun Yi6967b772019-02-22 13:48:12 -0800384 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800385 log<level::ERR>("No open blob to write");
Kun Yi6967b772019-02-22 13:48:12 -0800386 return false;
387 }
388
389 if (!writable_)
390 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800391 log<level::ERR>("Open blob is not writable");
Kun Yi6967b772019-02-22 13:48:12 -0800392 return false;
393 }
394
William A. Kennington III7e145862024-02-01 15:56:33 -0800395 auto& bdata = blobs_.find(currentBlob_)->second;
396 if (offset > bdata.size())
Kun Yi6967b772019-02-22 13:48:12 -0800397 {
Kun Yi8bcf79d2019-01-16 15:17:57 -0800398 log<level::ERR>("Write would leave a gap with undefined data. Return.");
Kun Yi6967b772019-02-22 13:48:12 -0800399 return false;
400 }
401
William A. Kennington III7e145862024-02-01 15:56:33 -0800402 std::size_t oldsize = bdata.size(), reqSize = offset + data.size();
403 if (reqSize > bdata.size())
404 {
405 bdata.resize(reqSize);
406 }
Willy Tu67391d52021-12-07 19:53:49 -0800407
William A. Kennington III7e145862024-02-01 15:56:33 -0800408 if (payloadCalcSize(makeEncoder(baseBlobId_, blobs_)) >
409 maxSize.value_or(
410 std::numeric_limits<std::decay_t<decltype(*maxSize)>>::max()))
Willy Tu67391d52021-12-07 19:53:49 -0800411 {
412 log<level::ERR>("Write data would make the total size exceed the max "
413 "size allowed. Return.");
William A. Kennington III7e145862024-02-01 15:56:33 -0800414 bdata.resize(oldsize);
Willy Tu67391d52021-12-07 19:53:49 -0800415 return false;
416 }
417
Kun Yi1a25e0d2020-05-11 12:28:53 -0700418 commitState_ = CommitState::Dirty;
William A. Kennington III7e145862024-02-01 15:56:33 -0800419 std::copy(data.begin(), data.end(), bdata.data() + offset);
Kun Yi6967b772019-02-22 13:48:12 -0800420 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800421}
422
423bool BinaryStore::commit()
424{
Maksym Sloykoeb274112021-10-27 23:48:32 +0000425 if (readOnly_)
426 {
427 log<level::ERR>("ReadOnly blob, not committing");
428 return false;
429 }
430
Kun Yi70059172019-02-22 16:31:42 -0800431 /* Store as little endian to be platform agnostic. Consistent with read. */
William A. Kennington III7e145862024-02-01 15:56:33 -0800432 auto msg = makeEncoder(baseBlobId_, blobs_);
433 auto outSize = payloadCalcSize(msg);
434 if (outSize >
435 maxSize.value_or(
436 std::numeric_limits<std::decay_t<decltype(*maxSize)>>::max()))
Willy Tu67391d52021-12-07 19:53:49 -0800437 {
Willy Tu91633852022-02-18 08:55:43 -0800438 log<level::ERR>("Commit Data exceeded maximum allowed size");
Willy Tu67391d52021-12-07 19:53:49 -0800439 return false;
440 }
William A. Kennington III7e145862024-02-01 15:56:33 -0800441 std::string buf(outSize, '\0');
442 auto& size = *reinterpret_cast<boost::endian::little_uint64_t*>(buf.data());
443 auto ost = pb_ostream_from_buffer(reinterpret_cast<pb_byte_t*>(buf.data()) +
444 sizeof(size),
445 buf.size() - sizeof(size));
446 pb_encode(&ost, binstore_binaryblobproto_BinaryBlobBase_fields, &msg);
447 size = ost.bytes_written;
Kun Yid297c9f2019-01-09 13:52:30 -0800448 try
449 {
William A. Kennington III7e145862024-02-01 15:56:33 -0800450 file_->writeStr(buf, 0);
Kun Yid297c9f2019-01-09 13:52:30 -0800451 }
452 catch (const std::exception& e)
453 {
Kun Yid297c9f2019-01-09 13:52:30 -0800454 commitState_ = CommitState::CommitError;
Kun Yi8bcf79d2019-01-16 15:17:57 -0800455 log<level::ERR>("Writing to sysfile failed",
456 entry("ERROR=%s", e.what()));
Kun Yid297c9f2019-01-09 13:52:30 -0800457 return false;
458 };
459
460 commitState_ = CommitState::Clean;
461 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800462}
463
464bool BinaryStore::close()
465{
William A. Kennington III7e145862024-02-01 15:56:33 -0800466 currentBlob_.clear();
Kun Yi6baa7132019-01-08 21:21:02 -0800467 writable_ = false;
Kun Yid297c9f2019-01-09 13:52:30 -0800468 commitState_ = CommitState::Dirty;
Kun Yi6baa7132019-01-08 21:21:02 -0800469 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800470}
471
Kun Yi1a25e0d2020-05-11 12:28:53 -0700472/*
473 * Sets |meta| with size and state of the blob. Returns |blobState| with
474 * standard definition from phosphor-ipmi-blobs header blob.hpp, plus OEM
475 * flag bits BinaryStore::CommitState.
476
477enum StateFlags
Kun Yi64dc05c2018-12-19 13:19:03 -0800478{
Kun Yi1a25e0d2020-05-11 12:28:53 -0700479 open_read = (1 << 0),
480 open_write = (1 << 1),
481 committing = (1 << 2),
482 committed = (1 << 3),
483 commit_error = (1 << 4),
484};
485
486enum CommitState
487{
488 Dirty = (1 << 8), // In-memory data might not match persisted data
489 Clean = (1 << 9), // In-memory data matches persisted data
490 Uninitialized = (1 << 10), // Cannot find persisted data
491 CommitError = (1 << 11) // Error happened during committing
492};
493
494*/
495bool BinaryStore::stat(blobs::BlobMeta* meta)
496{
497 uint16_t blobState = blobs::StateFlags::open_read;
498 if (writable_)
499 {
500 blobState |= blobs::StateFlags::open_write;
501 }
502
503 if (commitState_ == CommitState::Clean)
504 {
505 blobState |= blobs::StateFlags::committed;
506 }
507 else if (commitState_ == CommitState::CommitError)
508 {
509 blobState |= blobs::StateFlags::commit_error;
510 }
511 blobState |= commitState_;
512
William A. Kennington III7e145862024-02-01 15:56:33 -0800513 if (!currentBlob_.empty())
Kun Yi1a25e0d2020-05-11 12:28:53 -0700514 {
William A. Kennington III7e145862024-02-01 15:56:33 -0800515 meta->size = blobs_.find(currentBlob_)->second.size();
Kun Yi1a25e0d2020-05-11 12:28:53 -0700516 }
517 else
518 {
519 meta->size = 0;
520 }
521 meta->blobState = blobState;
522
523 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800524}
525
526} // namespace binstore