blob: dff423ef84537a7d25816e766dac400c52bc055a [file] [log] [blame]
Kun Yi64dc05c2018-12-19 13:19:03 -08001#include "binarystore.hpp"
2
Kun Yid2d8cb62019-01-10 15:06:12 -08003#include <unistd.h>
4
Kun Yi6baa7132019-01-08 21:21:02 -08005#include <algorithm>
6#include <blobs-ipmid/blobs.hpp>
Kun Yi70059172019-02-22 16:31:42 -08007#include <boost/endian/arithmetic.hpp>
Kun Yid2d8cb62019-01-10 15:06:12 -08008#include <cstdint>
9#include <memory>
10#include <string>
11#include <vector>
12
13#include "binaryblob.pb.h"
14
15using std::size_t;
16using std::uint16_t;
17using std::uint32_t;
18using std::uint64_t;
19using std::uint8_t;
Kun Yi6baa7132019-01-08 21:21:02 -080020
Kun Yi64dc05c2018-12-19 13:19:03 -080021namespace binstore
22{
23
24std::unique_ptr<BinaryStoreInterface>
25 BinaryStore::createFromConfig(const std::string& baseBlobId,
Kun Yi2765b642019-01-16 11:11:24 -080026 std::unique_ptr<SysFile> file,
27 uint32_t maxSize)
Kun Yi64dc05c2018-12-19 13:19:03 -080028{
Kun Yi2765b642019-01-16 11:11:24 -080029 if (baseBlobId.empty() || !file)
30 {
31 return nullptr;
32 }
33
34 auto store =
35 std::make_unique<BinaryStore>(baseBlobId, std::move(file), maxSize);
36
37 store->blob_.set_blob_base_id(store->baseBlobId_);
38
39 return std::move(store);
Kun Yi64dc05c2018-12-19 13:19:03 -080040}
41
42std::string BinaryStore::getBaseBlobId() const
43{
44 return baseBlobId_;
45}
46
47std::vector<std::string> BinaryStore::getBlobIds() const
48{
49 std::vector<std::string> result;
50 result.push_back(baseBlobId_);
51
Kun Yi0a940b92019-01-07 16:33:11 -080052 for (const auto& blob : blob_.blobs())
Kun Yi64dc05c2018-12-19 13:19:03 -080053 {
Kun Yi0a940b92019-01-07 16:33:11 -080054 result.push_back(blob.blob_id());
Kun Yi64dc05c2018-12-19 13:19:03 -080055 }
56
57 return result;
58}
59
60bool BinaryStore::openOrCreateBlob(const std::string& blobId, uint16_t flags)
61{
Kun Yi6baa7132019-01-08 21:21:02 -080062 if (!(flags & blobs::OpenFlags::read))
63 {
64 return false;
65 }
66
67 if (currentBlob_ && (currentBlob_->blob_id() != blobId))
68 {
69 /* Already handling a different blob */
70 return false;
71 }
72
73 writable_ = flags & blobs::OpenFlags::write;
74
Kun Yid297c9f2019-01-09 13:52:30 -080075 /* Load blob from sysfile if we know it might not match what we have.
76 * Note it will overwrite existing unsaved data per design. */
77 if (commitState_ != CommitState::Clean)
78 {
79 try
80 {
81 /* Parse length-prefixed format to protobuf */
Kun Yi70059172019-02-22 16:31:42 -080082 boost::endian::little_uint64_t size = 0;
83 file_->readToBuf(0, sizeof(size), reinterpret_cast<char*>(&size));
84
Kun Yid297c9f2019-01-09 13:52:30 -080085 if (!blob_.ParseFromString(
86 file_->readAsStr(sizeof(uint64_t), size)))
87 {
88 /* Fail to parse the data, which might mean no preexsiting data
89 * and is a valid case to handle */
90 // TODO: logging
91 }
92 }
93 catch (const std::exception& e)
94 {
95 /* Read causes unexpected system-level failure */
96 // TODO: logging
97 return false;
98 }
99 }
100
Kun Yi6baa7132019-01-08 21:21:02 -0800101 /* Iterate and find if there is an existing blob with this id.
102 * blobsPtr points to a BinaryBlob container with STL-like semantics*/
103 auto blobsPtr = blob_.mutable_blobs();
104 auto blobIt =
105 std::find_if(blobsPtr->begin(), blobsPtr->end(),
106 [&](const auto& b) { return b.blob_id() == blobId; });
107
108 if (blobIt != blobsPtr->end())
109 {
110 currentBlob_ = &(*blobIt);
111 return true;
112 }
113
114 /* Otherwise, create the blob and append it */
115 currentBlob_ = blob_.add_blobs();
116 currentBlob_->set_blob_id(blobId);
117
118 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800119}
120
121bool BinaryStore::deleteBlob(const std::string& blobId)
122{
123 return false;
124}
125
126std::vector<uint8_t> BinaryStore::read(uint32_t offset, uint32_t requestedSize)
127{
Kun Yi6967b772019-02-22 13:48:12 -0800128 std::vector<uint8_t> result;
129
130 if (!currentBlob_)
131 {
132 return result;
133 }
134
135 auto dataPtr = currentBlob_->mutable_data();
136
137 /* If it is out of bound, return empty vector */
138 if (offset >= dataPtr->size())
139 {
140 return result;
141 }
142
143 uint32_t requestedEndPos = offset + requestedSize;
144
145 result = std::vector<uint8_t>(
146 dataPtr->begin() + offset,
147 std::min(dataPtr->begin() + requestedEndPos, dataPtr->end()));
Kun Yi64dc05c2018-12-19 13:19:03 -0800148 return result;
149}
150
151bool BinaryStore::write(uint32_t offset, const std::vector<uint8_t>& data)
152{
Kun Yi6967b772019-02-22 13:48:12 -0800153 if (!currentBlob_)
154 {
155 return false;
156 }
157
158 if (!writable_)
159 {
160 return false;
161 }
162
163 auto dataPtr = currentBlob_->mutable_data();
164
165 if (offset > dataPtr->size())
166 {
167 /* Will leave a gap with undefined data */
168 return false;
169 }
170
171 /* Copy (overwrite) the data */
172 if (offset + data.size() > dataPtr->size())
173 {
174 dataPtr->resize(offset + data.size()); // not enough space, extend
175 }
176 std::copy(data.begin(), data.end(), dataPtr->begin() + offset);
177 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800178}
179
180bool BinaryStore::commit()
181{
Kun Yi70059172019-02-22 16:31:42 -0800182 /* Store as little endian to be platform agnostic. Consistent with read. */
Kun Yid297c9f2019-01-09 13:52:30 -0800183 auto blobData = blob_.SerializeAsString();
Kun Yi70059172019-02-22 16:31:42 -0800184 boost::endian::little_uint64_t sizeLE = blobData.size();
185 std::string commitData(sizeLE.data(), sizeof(sizeLE));
Kun Yid297c9f2019-01-09 13:52:30 -0800186 commitData += blobData;
187
188 try
189 {
190 file_->writeStr(commitData, 0);
191 }
192 catch (const std::exception& e)
193 {
Kun Yid297c9f2019-01-09 13:52:30 -0800194 commitState_ = CommitState::CommitError;
195 return false;
196 };
197
198 commitState_ = CommitState::Clean;
199 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800200}
201
202bool BinaryStore::close()
203{
Kun Yi6baa7132019-01-08 21:21:02 -0800204 currentBlob_ = nullptr;
205 writable_ = false;
Kun Yid297c9f2019-01-09 13:52:30 -0800206 commitState_ = CommitState::Dirty;
Kun Yi6baa7132019-01-08 21:21:02 -0800207 return true;
Kun Yi64dc05c2018-12-19 13:19:03 -0800208}
209
210bool BinaryStore::stat()
211{
212 return false;
213}
214
215} // namespace binstore