libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
key_ops.hpp
1
29size_t GetKeyData(size_t offset)
30{
31 KeyInfo key;
32 ReadFlashOrExit(offset, key);
33 return offset + AlignSize(sizeof(KeyInfo)) + AlignSize(key.GetNameLength());
34}
35
42size_t GetKeyName(size_t offset) { return offset + AlignSize(sizeof(KeyInfo)); }
43
50size_t GetKeySpan(const KeyInfo& key)
51{
52 return AlignSize(sizeof(KeyInfo)) + AlignSize(key.GetNameLength()) +
53 AlignSize(key.GetDataSize());
54}
55
61size_t GetKeySize(size_t offset)
62{
63 KeyInfo key;
64 ReadFlashOrExit(offset, key);
65 return GetKeySpan(key);
66}
67
73size_t GetNextKey(size_t offset) { return offset + GetKeySize(offset); }
74
81static bool IsKeyLive(const KeyInfo& key)
82{
85}
86
95void ClearKeyFlag(size_t key_offset, BlockBoolData<MinWriteSize> KeyInfo::* flag)
96{
97 const size_t flag_offset = key_offset + LibXR::OffsetOf(flag);
99 ReadFlashOrExit(flag_offset, value);
101 {
102 return;
103 }
105 WriteFlashOrExit(flag_offset, value);
106}
107
118void LinkKey(BlockType block, size_t last_key_offset)
119{
120 if (last_key_offset == GetSentinelOffset(block))
121 {
122 ClearKeyFlag(last_key_offset, &KeyInfo::available_flag);
123 }
124 ClearKeyFlag(last_key_offset, &KeyInfo::no_next_key);
125}
126
135void WriteKeyHeader(size_t key_offset, size_t name_len, size_t size)
136{
137 KeyInfo key;
138 key.SetNameLength(static_cast<uint8_t>(name_len));
139 key.SetDataSize(static_cast<uint32_t>(size));
140 WriteFlashOrExit(key_offset + LibXR::OffsetOf(&KeyInfo::raw_info), key.raw_info);
141}
142
157bool NextChainKey(BlockType block, size_t& key_offset, KeyInfo& key)
158{
160 {
161 return false;
162 }
163
164 const size_t limit = GetBlockOffset(block) + GetChecksumOffset();
165 const size_t next_offset = key_offset + GetKeySpan(key);
166 if (next_offset + AlignSize(sizeof(KeyInfo)) > limit)
167 {
168 return false;
169 }
170
171 KeyInfo next_key;
172 ReadFlashOrExit(next_offset, next_key);
173 if (next_offset + GetKeySpan(next_key) > limit)
174 {
175 return false;
176 }
177
178 key_offset = next_offset;
179 key = next_key;
180 return true;
181}
182
189size_t GetLastKey(BlockType block)
190{
191 size_t key_offset = GetSentinelOffset(block);
192 KeyInfo key;
193 ReadFlashOrExit(key_offset, key);
194 while (NextChainKey(block, key_offset, key))
195 {
196 }
197 return key_offset;
198}
199
209bool KeyDataCompare(size_t offset, const void* data, size_t size)
210{
211 KeyInfo key;
212 ReadFlashOrExit(offset, key);
213 size_t key_data_offset = GetKeyData(offset);
214 uint8_t data_buffer = 0;
215 for (size_t i = 0; i < size; i++)
216 {
217 ReadFlashOrExit(key_data_offset + i, data_buffer);
218 if (data_buffer != (reinterpret_cast<const uint8_t*>(data))[i])
219 {
220 return true;
221 }
222 }
223 return false;
224}
225
234bool KeyNameCompare(size_t offset, const char* name)
235{
236 KeyInfo key;
237 ReadFlashOrExit(offset, key);
238 for (size_t i = 0; i < key.GetNameLength(); i++)
239 {
240 uint8_t data_buffer = 0;
241 ReadFlashOrExit(offset + AlignSize(sizeof(KeyInfo)) + i, data_buffer);
242 if (data_buffer != name[i])
243 {
244 return true;
245 }
246 }
247 return false;
248}
249
262bool IsKeyNameTerminated(size_t key_offset, const KeyInfo& key)
263{
264 const size_t name_len = key.GetNameLength();
265 if (name_len == 0)
266 {
267 return false;
268 }
269 uint8_t last_byte = 0xFF;
270 ReadFlashOrExit(GetKeyName(key_offset) + name_len - 1, last_byte);
271 return last_byte == 0;
272}
273
283size_t FindKey(const char* name, size_t& dead_keys)
284{
285 size_t key_offset = GetSentinelOffset(BlockType::MAIN);
286 KeyInfo key;
287 ReadFlashOrExit(key_offset, key);
288 dead_keys = 0;
289
290 while (NextChainKey(BlockType::MAIN, key_offset, key))
291 {
292 if (!IsKeyLive(key))
293 {
294 dead_keys++;
295 continue;
296 }
297 if (!KeyNameCompare(key_offset, name))
298 {
299 return key_offset;
300 }
301 }
302 return 0;
303}
304
318size_t SearchKey(const char* name)
319{
320 size_t dead_keys = 0;
321 const size_t ans = FindKey(name, dead_keys);
322 if (dead_keys > recycle_threshold_)
323 {
324 Recycle();
325 return FindKey(name, dead_keys);
326 }
327 return ans;
328}
329
342ErrorCode ReserveKey(size_t name_len, size_t size, size_t& last_key_offset)
343{
344 const size_t needed =
345 AlignSize(sizeof(KeyInfo)) + AlignSize(name_len) + AlignSize(size);
346 if (AvailableSize() < needed)
347 {
348 Recycle();
349 if (AvailableSize() < needed)
350 {
351 return ErrorCode::FULL;
352 }
353 }
354 last_key_offset = GetLastKey(BlockType::MAIN);
355 return ErrorCode::OK;
356}
357
365ErrorCode AddKey(const char* name, const void* data, size_t size)
366{
367 if (SearchKey(name))
368 {
369 return SetKey(name, data, size);
370 }
371
372 const size_t name_len = strlen(name) + 1;
373 size_t last_key_offset = 0;
374 const ErrorCode ec = ReserveKey(name_len, size, last_key_offset);
375 if (ec != ErrorCode::OK)
376 {
377 return ec;
378 }
379
380 const size_t key_offset = GetNextKey(last_key_offset);
381 WriteKeyHeader(key_offset, name_len, size);
382 WriteFlashOrExit(GetKeyName(key_offset),
383 {reinterpret_cast<const uint8_t*>(name), name_len});
384 WriteFlashOrExit(GetKeyData(key_offset),
385 {reinterpret_cast<const uint8_t*>(data), size});
386 ClearKeyFlag(key_offset, &KeyInfo::uninit);
387 LinkKey(BlockType::MAIN, last_key_offset);
388 return ErrorCode::OK;
389}
390
410ErrorCode SetKey(const char* name, const void* data, size_t size, bool recycle = true)
411{
412 const size_t key_offset = SearchKey(name);
413 if (!key_offset)
414 {
415 return ErrorCode::FAILED;
416 }
417
418 KeyInfo key;
419 ReadFlashOrExit(key_offset, key);
420 if (key.GetDataSize() != size)
421 {
422 return ErrorCode::FAILED;
423 }
424 if (!KeyDataCompare(key_offset, data, size))
425 {
426 return ErrorCode::OK;
427 }
428
429 const size_t name_len = key.GetNameLength();
430 if (AvailableSize() <
431 AlignSize(sizeof(KeyInfo)) + AlignSize(name_len) + AlignSize(size))
432 {
433 if (!recycle)
434 {
435 return ErrorCode::FULL;
436 }
437 Recycle();
438 return SetKey(name, data, size, false);
439 }
440
441 const size_t last_key_offset = GetLastKey(BlockType::MAIN);
442 const size_t new_key_offset = GetNextKey(last_key_offset);
443 WriteKeyHeader(new_key_offset, name_len, size);
444 CopyFlashData(GetKeyName(new_key_offset), GetKeyName(key_offset), name_len);
445 WriteFlashOrExit(GetKeyData(new_key_offset),
446 {reinterpret_cast<const uint8_t*>(data), size});
447 ClearKeyFlag(new_key_offset, &KeyInfo::uninit);
448 ClearKeyFlag(key_offset, &KeyInfo::available_flag);
449 LinkKey(BlockType::MAIN, last_key_offset);
450 return ErrorCode::OK;
451}
452
469bool CompleteUnlinkedKey(size_t last_key_offset, size_t key_offset)
470{
471 const size_t checksum_offset = GetChecksumOffset();
472 if (key_offset + AlignSize(sizeof(KeyInfo)) > checksum_offset)
473 {
474 return false;
475 }
476
477 KeyInfo key;
478 ReadFlashOrExit(key_offset, key);
479 const size_t end_offset = key_offset + GetKeySpan(key);
480 if (!BlockBoolUtil<MinWriteSize>::ReadFlag(key.no_next_key) || !IsKeyLive(key) ||
481 end_offset > checksum_offset || !IsKeyNameTerminated(key_offset, key) ||
482 !IsErased(end_offset, checksum_offset))
483 {
484 return false;
485 }
486
487 char name[0x80] = {};
488 ReadFlashOrExit(GetKeyName(key_offset), RawData(name, key.GetNameLength()));
489 size_t dead_keys = 0;
490 const size_t old_offset = FindKey(name, dead_keys);
491 if (old_offset != 0)
492 {
493 KeyInfo old_key;
494 ReadFlashOrExit(old_offset, old_key);
495 if (old_key.GetDataSize() != key.GetDataSize())
496 {
497 return false;
498 }
499 ClearKeyFlag(old_offset, &KeyInfo::available_flag);
500 }
501
502 LinkKey(BlockType::MAIN, last_key_offset);
503 return true;
504}
505
519void RepairMainChain()
520{
521 size_t key_offset = GetSentinelOffset(BlockType::MAIN);
522 KeyInfo key;
523 ReadFlashOrExit(key_offset, key);
524 size_t dead_keys = 0;
525 while (NextChainKey(BlockType::MAIN, key_offset, key))
526 {
527 if (!IsKeyLive(key))
528 {
529 dead_keys++;
530 }
531 }
532
533 const bool chain_complete = BlockBoolUtil<MinWriteSize>::ReadFlag(key.no_next_key);
534 const size_t tail_offset = key_offset + GetKeySpan(key);
535 if (chain_complete && IsErased(tail_offset, GetChecksumOffset()))
536 {
537 if (dead_keys > recycle_threshold_)
538 {
539 Recycle();
540 }
541 return;
542 }
543
544 if (chain_complete && CompleteUnlinkedKey(key_offset, tail_offset))
545 {
546 return;
547 }
548
549 // Recycle() 只在整理后的键加上 CRC 单元放不下时返回 FULL,而链尾之后的残留至少占一个
550 // 键头,不小于 CRC 单元,所以需要清理残留时回收总能进行。
551 // Recycle() returns FULL only when the compacted keys plus the CRC unit do not fit,
552 // and leftovers after the chain take at least one key header, no smaller than the CRC
553 // unit, so a recycle can always run when leftovers have to be cleared.
554 Recycle();
555}
读写对齐布尔位图块的工具 Helpers for reading and writing aligned boolean flag blocks.
Definition layout.hpp:36
static void SetFlag(BlockBoolData< BlockSize > &obj, bool value)
把一个布尔值编码进位图块 / Encode one boolean value into a flag block.
Definition layout.hpp:43
static bool ReadFlag(const BlockBoolData< BlockSize > &obj)
从位图块读取布尔值 / Decode one boolean value from a flag block.
Definition layout.hpp:64
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
size_t OffsetOf(MemberType OwnerType::*member) noexcept
计算成员在宿主对象中的偏移量 Computes the offset of a member within the owning object
Definition libxr_def.hpp:95
按最小写入单元存放布尔位图块 Boolean flag block stored in one aligned write unit span.
Definition layout.hpp:24
键信息结构,存储键的元数据 Structure containing key metadata.
Definition layout.hpp:119
BlockBoolData< MinWriteSize > uninit
该键是否未初始化
Definition layout.hpp:122
BlockBoolData< MinWriteSize > available_flag
该键是否有效
Definition layout.hpp:121
uint32_t GetDataSize() const
获取数据字节数 / Get the payload size in bytes.
Definition layout.hpp:167
uint32_t raw_info
Definition layout.hpp:124
void SetNameLength(uint8_t len)
设置键名长度 / Set the key name length.
Definition layout.hpp:143
BlockBoolData< MinWriteSize > no_next_key
是否是最后一个键
Definition layout.hpp:120
void SetDataSize(uint32_t size)
设置数据字节数 / Set the payload size in bytes.
Definition layout.hpp:158
uint8_t GetNameLength() const
获取键名长度 / Get the key name length.
Definition layout.hpp:152