mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-07 05:40:59 +02:00
Merge branch 'bugfix/nvs_entry_sanity_check_v5.1' into 'release/v5.1'
Bugfix/added nvs entry header sanity checks (v5.1) See merge request espressif/esp-idf!34295
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -547,8 +547,8 @@ TEST_CASE("readonly handle fails on writing", "[nvs]")
|
||||
TEMPORARILY_DISABLED(f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);)
|
||||
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
|
||||
// first, creating namespace...
|
||||
TEST_ESP_OK(nvs_open("ro_ns", NVS_READWRITE, &handle_1));
|
||||
@@ -575,14 +575,13 @@ TEST_CASE("nvs api tests", "[nvs]")
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
TEMPORARILY_DISABLED(f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);)
|
||||
|
||||
|
||||
TEST_ESP_ERR(nvs_open("namespace1", NVS_READWRITE, &handle_1), ESP_ERR_NVS_NOT_INITIALIZED);
|
||||
for (uint16_t i = NVS_FLASH_SECTOR; i < NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; ++i) {
|
||||
TEMPORARILY_DISABLED(f.emu.erase(i);)
|
||||
}
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
|
||||
TEST_ESP_ERR(nvs_open("namespace1", NVS_READONLY, &handle_1), ESP_ERR_NVS_NOT_FOUND);
|
||||
|
||||
@@ -643,11 +642,11 @@ TEST_CASE("deinit partition doesn't affect other partition's open handles", "[nv
|
||||
TEMPORARILY_DISABLED(f_other.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);)
|
||||
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f_other.part(),
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
|
||||
TEST_ESP_OK(nvs_open_from_partition(OTHER_PARTITION_NAME, "ns", NVS_READWRITE, &handle_1));
|
||||
|
||||
@@ -715,8 +714,8 @@ TEST_CASE("nvs iterators tests", "[nvs]")
|
||||
TEMPORARILY_DISABLED(f.emu.erase(i);)
|
||||
}
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
|
||||
nvs_iterator_t it;
|
||||
nvs_entry_info_t info;
|
||||
@@ -748,8 +747,7 @@ TEST_CASE("nvs iterators tests", "[nvs]")
|
||||
int count = 0;
|
||||
nvs_iterator_t it = nullptr;
|
||||
esp_err_t res = nvs_entry_find(part, name, type, &it);
|
||||
for (count = 0; res == ESP_OK; count++)
|
||||
{
|
||||
for (count = 0; res == ESP_OK; count++) {
|
||||
res = nvs_entry_next(&it);
|
||||
}
|
||||
CHECK(res == ESP_ERR_NVS_NOT_FOUND); // after finishing the loop or if no entry was found to begin with,
|
||||
@@ -858,14 +856,13 @@ TEST_CASE("nvs iterators tests", "[nvs]")
|
||||
nvs_release_iterator(it);
|
||||
}
|
||||
|
||||
|
||||
SECTION("Iterating over multiple pages works correctly") {
|
||||
nvs_handle_t handle_3;
|
||||
const char *name_3 = "namespace3";
|
||||
const int entries_created = 250;
|
||||
|
||||
TEST_ESP_OK(nvs_open(name_3, NVS_READWRITE, &handle_3));
|
||||
for (size_t i = 0; i < entries_created; i++) {
|
||||
for (size_t i = 0; i < entries_created; i++) {
|
||||
TEST_ESP_OK(nvs_set_u8(handle_3, to_string(i).c_str(), 123));
|
||||
}
|
||||
|
||||
@@ -922,8 +919,8 @@ TEST_CASE("Iterator with not matching type iterates correctly", "[nvs]")
|
||||
TEMPORARILY_DISABLED(f.emu.erase(i);)
|
||||
}
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
|
||||
// writing string to namespace (a type which spans multiple entries)
|
||||
TEST_ESP_OK(nvs_open(NAMESPACE, NVS_READWRITE, &my_handle));
|
||||
@@ -936,8 +933,8 @@ TEST_CASE("Iterator with not matching type iterates correctly", "[nvs]")
|
||||
// re-init to trigger cleaning up of broken items -> a corrupted string will be erased
|
||||
nvs_flash_deinit();
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
|
||||
CHECK(nvs_entry_find(NVS_DEFAULT_PART_NAME, NAMESPACE, NVS_TYPE_STR, &it) == ESP_OK);
|
||||
nvs_release_iterator(it);
|
||||
@@ -955,8 +952,8 @@ TEST_CASE("wifi test", "[nvs]")
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
TEMPORARILY_DISABLED(f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);)
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
|
||||
nvs_handle_t misc_handle;
|
||||
TEST_ESP_OK(nvs_open("nvs.net80211", NVS_READWRITE, &misc_handle));
|
||||
@@ -1123,8 +1120,7 @@ public:
|
||||
static_assert(nKeys == sizeof(values) / sizeof(values[0]), "");
|
||||
|
||||
auto randomRead = [&](size_t index) -> esp_err_t {
|
||||
switch (types[index])
|
||||
{
|
||||
switch (types[index]) {
|
||||
case nvs::ItemType::I32: {
|
||||
int32_t val;
|
||||
auto err = nvs_get_i32(handle, keys[index], &val);
|
||||
@@ -1204,8 +1200,7 @@ public:
|
||||
};
|
||||
|
||||
auto randomWrite = [&](size_t index) -> esp_err_t {
|
||||
switch (types[index])
|
||||
{
|
||||
switch (types[index]) {
|
||||
case nvs::ItemType::I32: {
|
||||
int32_t val = static_cast<int32_t>(gen());
|
||||
|
||||
@@ -1323,7 +1318,7 @@ public:
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t handleExternalWriteAtIndex(uint8_t index, const void *value, const size_t len )
|
||||
esp_err_t handleExternalWriteAtIndex(uint8_t index, const void *value, const size_t len)
|
||||
{
|
||||
if (index == 9) { /* This is only done for small-page blobs for now*/
|
||||
if (len > smallBlobLen) {
|
||||
@@ -1354,8 +1349,8 @@ TEST_CASE("monkey test", "[nvs][monkey]")
|
||||
TEMPORARILY_DISABLED(f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);)
|
||||
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
|
||||
nvs_handle_t handle;
|
||||
TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
|
||||
@@ -1375,8 +1370,8 @@ TEST_CASE("test for memory leaks in open/set", "[leaks]")
|
||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
||||
TEMPORARILY_DISABLED(f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);)
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
|
||||
for (int i = 0; i < 100000; ++i) {
|
||||
nvs_handle_t light_handle = 0;
|
||||
@@ -1405,7 +1400,7 @@ TEST_CASE("read/write failure (TW8406)", "[nvs]")
|
||||
ESP_ERROR_CHECK(nvs_open("LIGHT", NVS_READWRITE, &light_handle));
|
||||
ESP_ERROR_CHECK(nvs_set_u8(light_handle, "RecordNum", number));
|
||||
for (i = 0; i < number; ++i) {
|
||||
sprintf(key, "light%d", i);
|
||||
snprintf(key, sizeof(key), "light%d", i);
|
||||
ESP_ERROR_CHECK(nvs_set_blob(light_handle, key, data, sizeof(data)));
|
||||
}
|
||||
nvs_commit(light_handle);
|
||||
@@ -1415,7 +1410,7 @@ TEST_CASE("read/write failure (TW8406)", "[nvs]")
|
||||
REQUIRE(number == get_number);
|
||||
for (i = 0; i < number; ++i) {
|
||||
char data[76] = {0};
|
||||
sprintf(key, "light%d", i);
|
||||
snprintf(key, sizeof(key), "light%d", i);
|
||||
ESP_ERROR_CHECK(nvs_get_blob(light_handle, key, data, &data_len));
|
||||
}
|
||||
nvs_close(light_handle);
|
||||
@@ -1429,22 +1424,22 @@ TEST_CASE("nvs_flash_init checks for an empty page", "[nvs]")
|
||||
const size_t blob_size = nvs::Page::CHUNK_MAX_SIZE;
|
||||
uint8_t blob[blob_size] = {0};
|
||||
PartitionEmulationFixture f(0, 8);
|
||||
TEST_ESP_OK( nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 5) );
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 5));
|
||||
nvs_handle_t handle;
|
||||
TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) );
|
||||
TEST_ESP_OK(nvs_open("test", NVS_READWRITE, &handle));
|
||||
// Fill first page
|
||||
TEST_ESP_OK( nvs_set_blob(handle, "1a", blob, blob_size) );
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "1a", blob, blob_size));
|
||||
// Fill second page
|
||||
TEST_ESP_OK( nvs_set_blob(handle, "2a", blob, blob_size) );
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "2a", blob, blob_size));
|
||||
// Fill third page
|
||||
TEST_ESP_OK( nvs_set_blob(handle, "3a", blob, blob_size) );
|
||||
TEST_ESP_OK( nvs_commit(handle) );
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "3a", blob, blob_size));
|
||||
TEST_ESP_OK(nvs_commit(handle));
|
||||
nvs_close(handle);
|
||||
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
|
||||
// first two pages are now full, third one is writable, last two are empty
|
||||
// init should fail
|
||||
TEST_ESP_ERR( nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 3),
|
||||
ESP_ERR_NVS_NO_FREE_PAGES );
|
||||
TEST_ESP_ERR(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 3),
|
||||
ESP_ERR_NVS_NO_FREE_PAGES);
|
||||
|
||||
// in case this test fails, to not affect other tests
|
||||
nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME);
|
||||
@@ -1455,19 +1450,19 @@ TEST_CASE("nvs page selection takes into account free entries also not just eras
|
||||
const size_t blob_size = nvs::Page::CHUNK_MAX_SIZE / 2;
|
||||
uint8_t blob[blob_size] = {0};
|
||||
PartitionEmulationFixture f(0, 3);
|
||||
TEST_ESP_OK( nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 3) );
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 3));
|
||||
nvs_handle_t handle;
|
||||
TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) );
|
||||
TEST_ESP_OK(nvs_open("test", NVS_READWRITE, &handle));
|
||||
// Fill first page
|
||||
TEST_ESP_OK( nvs_set_blob(handle, "1a", blob, blob_size / 3) );
|
||||
TEST_ESP_OK( nvs_set_blob(handle, "1b", blob, blob_size) );
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "1a", blob, blob_size / 3));
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "1b", blob, blob_size));
|
||||
// Fill second page
|
||||
TEST_ESP_OK( nvs_set_blob(handle, "2a", blob, blob_size) );
|
||||
TEST_ESP_OK( nvs_set_blob(handle, "2b", blob, blob_size) );
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "2a", blob, blob_size));
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "2b", blob, blob_size));
|
||||
|
||||
// The item below should be able to fit the first page.
|
||||
TEST_ESP_OK( nvs_set_blob(handle, "3a", blob, 4) );
|
||||
TEST_ESP_OK( nvs_commit(handle) );
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "3a", blob, 4));
|
||||
TEST_ESP_OK(nvs_commit(handle));
|
||||
nvs_close(handle);
|
||||
|
||||
TEST_ESP_OK(nvs_flash_deinit_partition(f.part()->get_partition_name()));
|
||||
@@ -1672,21 +1667,21 @@ TEST_CASE("Modification of values for Multi-page blobs are supported", "[nvs]")
|
||||
uint8_t blob4[blob_size] = { 0x33};
|
||||
size_t read_size = blob_size;
|
||||
PartitionEmulationFixture f(0, 6);
|
||||
TEST_ESP_OK( nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 6) );
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 6));
|
||||
nvs_handle_t handle;
|
||||
memset(blob, 0x11, blob_size);
|
||||
memset(blob2, 0x22, blob_size);
|
||||
memset(blob3, 0x33, blob_size);
|
||||
memset(blob4, 0x44, blob_size);
|
||||
memset(blob_read, 0xff, blob_size);
|
||||
TEST_ESP_OK( nvs_open("test", NVS_READWRITE, &handle) );
|
||||
TEST_ESP_OK( nvs_set_blob(handle, "abc", blob, blob_size) );
|
||||
TEST_ESP_OK( nvs_set_blob(handle, "abc", blob2, blob_size) );
|
||||
TEST_ESP_OK( nvs_set_blob(handle, "abc", blob3, blob_size) );
|
||||
TEST_ESP_OK( nvs_set_blob(handle, "abc", blob4, blob_size) );
|
||||
TEST_ESP_OK( nvs_get_blob(handle, "abc", blob_read, &read_size));
|
||||
TEST_ESP_OK(nvs_open("test", NVS_READWRITE, &handle));
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size));
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "abc", blob2, blob_size));
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "abc", blob3, blob_size));
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "abc", blob4, blob_size));
|
||||
TEST_ESP_OK(nvs_get_blob(handle, "abc", blob_read, &read_size));
|
||||
CHECK(memcmp(blob4, blob_read, blob_size) == 0);
|
||||
TEST_ESP_OK( nvs_commit(handle) );
|
||||
TEST_ESP_OK(nvs_commit(handle));
|
||||
nvs_close(handle);
|
||||
|
||||
TEST_ESP_OK(nvs_flash_deinit_partition(f.part()->get_partition_name()));
|
||||
@@ -1699,14 +1694,14 @@ TEST_CASE("Modification from single page blob to multi-page", "[nvs]")
|
||||
uint8_t blob_read[blob_size] = {0xff};
|
||||
size_t read_size = blob_size;
|
||||
PartitionEmulationFixture f(0, 5);
|
||||
TEST_ESP_OK( nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 5) );
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 5));
|
||||
nvs_handle_t handle;
|
||||
TEST_ESP_OK(nvs_open("Test", NVS_READWRITE, &handle) );
|
||||
TEST_ESP_OK(nvs_open("Test", NVS_READWRITE, &handle));
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, nvs::Page::CHUNK_MAX_SIZE / 2));
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size));
|
||||
TEST_ESP_OK(nvs_get_blob(handle, "abc", blob_read, &read_size));
|
||||
CHECK(memcmp(blob, blob_read, blob_size) == 0);
|
||||
TEST_ESP_OK(nvs_commit(handle) );
|
||||
TEST_ESP_OK(nvs_commit(handle));
|
||||
nvs_close(handle);
|
||||
|
||||
TEST_ESP_OK(nvs_flash_deinit_partition(f.part()->get_partition_name()));
|
||||
@@ -1719,15 +1714,15 @@ TEST_CASE("Modification from multi-page to single page", "[nvs]")
|
||||
uint8_t blob_read[blob_size] = {0xff};
|
||||
size_t read_size = blob_size;
|
||||
PartitionEmulationFixture f(0, 5);
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 5) );
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 5));
|
||||
nvs_handle_t handle;
|
||||
TEST_ESP_OK(nvs_open("Test", NVS_READWRITE, &handle) );
|
||||
TEST_ESP_OK(nvs_open("Test", NVS_READWRITE, &handle));
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size));
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, nvs::Page::CHUNK_MAX_SIZE / 2));
|
||||
TEST_ESP_OK(nvs_set_blob(handle, "abc2", blob, blob_size));
|
||||
TEST_ESP_OK(nvs_get_blob(handle, "abc", blob_read, &read_size));
|
||||
CHECK(memcmp(blob, blob_read, nvs::Page::CHUNK_MAX_SIZE) == 0);
|
||||
TEST_ESP_OK(nvs_commit(handle) );
|
||||
TEST_ESP_OK(nvs_commit(handle));
|
||||
nvs_close(handle);
|
||||
|
||||
TEST_ESP_OK(nvs_flash_deinit_partition(f.part()->get_partition_name()));
|
||||
@@ -1765,7 +1760,6 @@ TEST_CASE("Check that orphaned blobs are erased during init", "[nvs]")
|
||||
|
||||
TEST_ESP_OK(storage.writeItem(1, nvs::ItemType::BLOB, "key", blob, sizeof(blob)));
|
||||
|
||||
|
||||
TEST_ESP_OK(storage.init(0, 5));
|
||||
/* Check that multi-page item is still available.**/
|
||||
TEST_ESP_OK(storage.readItem(1, nvs::ItemType::BLOB, "key", blob, sizeof(blob)));
|
||||
@@ -1785,21 +1779,21 @@ TEST_CASE("Check that orphaned blobs are erased during init", "[nvs]")
|
||||
TEST_CASE("nvs blob fragmentation test", "[nvs]")
|
||||
{
|
||||
PartitionEmulationFixture f(0, 4);
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 4) );
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 4));
|
||||
const size_t BLOB_SIZE = 3500;
|
||||
uint8_t *blob = (uint8_t *) malloc(BLOB_SIZE);
|
||||
CHECK(blob != NULL);
|
||||
memset(blob, 0xEE, BLOB_SIZE);
|
||||
const uint32_t magic = 0xff33eaeb;
|
||||
nvs_handle_t h;
|
||||
TEST_ESP_OK( nvs_open("blob_tests", NVS_READWRITE, &h) );
|
||||
TEST_ESP_OK(nvs_open("blob_tests", NVS_READWRITE, &h));
|
||||
for (int i = 0; i < 128; i++) {
|
||||
INFO("Iteration " << i << "...\n");
|
||||
TEST_ESP_OK( nvs_set_u32(h, "magic", magic) );
|
||||
TEST_ESP_OK( nvs_set_blob(h, "blob", blob, BLOB_SIZE) );
|
||||
TEST_ESP_OK(nvs_set_u32(h, "magic", magic));
|
||||
TEST_ESP_OK(nvs_set_blob(h, "blob", blob, BLOB_SIZE));
|
||||
char seq_buf[16];
|
||||
sprintf(seq_buf, "seq%d", i);
|
||||
TEST_ESP_OK( nvs_set_u32(h, seq_buf, i) );
|
||||
snprintf(seq_buf, sizeof(seq_buf), "seq%d", i);
|
||||
TEST_ESP_OK(nvs_set_u32(h, seq_buf, i));
|
||||
}
|
||||
free(blob);
|
||||
|
||||
@@ -1818,12 +1812,12 @@ TEST_CASE("nvs code handles errors properly when partition is near to full", "[n
|
||||
|
||||
/* Four pages should fit roughly 12 blobs*/
|
||||
for (uint8_t count = 1; count <= 12; count++) {
|
||||
sprintf(nvs_key, "key:%u", count);
|
||||
snprintf(nvs_key, sizeof(nvs_key), "key:%u", count);
|
||||
TEST_ESP_OK(storage.writeItem(1, nvs::ItemType::BLOB, nvs_key, blob, sizeof(blob)));
|
||||
}
|
||||
|
||||
for (uint8_t count = 13; count <= 20; count++) {
|
||||
sprintf(nvs_key, "key:%u", count);
|
||||
snprintf(nvs_key, sizeof(nvs_key), "key:%u", count);
|
||||
TEST_ESP_ERR(storage.writeItem(1, nvs::ItemType::BLOB, nvs_key, blob, sizeof(blob)), ESP_ERR_NVS_NOT_ENOUGH_SPACE);
|
||||
}
|
||||
}
|
||||
@@ -1864,14 +1858,14 @@ TEST_CASE("monkey test with old-format blob present", "[nvs][monkey]")
|
||||
TEMPORARILY_DISABLED(f.emu.setBounds(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN);)
|
||||
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
|
||||
nvs_handle_t handle;
|
||||
TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
|
||||
RandomTest test;
|
||||
|
||||
for ( uint8_t it = 0; it < 10; it++) {
|
||||
for (uint8_t it = 0; it < 10; it++) {
|
||||
size_t count = 200;
|
||||
|
||||
/* Erase index and chunks for the blob with "singlepage" key */
|
||||
@@ -1910,8 +1904,8 @@ TEST_CASE("monkey test with old-format blob present", "[nvs][monkey]")
|
||||
TEST_ESP_OK(nvs_flash_deinit_partition(f.part()->get_partition_name()));
|
||||
/* Initialize again */
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(),
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
NVS_FLASH_SECTOR,
|
||||
NVS_FLASH_SECTOR_COUNT_MIN));
|
||||
TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
|
||||
|
||||
/* Perform random things */
|
||||
@@ -1987,7 +1981,7 @@ TEST_CASE("Recovery from power-off during modification of blob present in old-fo
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 3));
|
||||
TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
|
||||
|
||||
TEST_ESP_OK( nvs_get_blob(handle, "singlepage", buf, &buflen));
|
||||
TEST_ESP_OK(nvs_get_blob(handle, "singlepage", buf, &buflen));
|
||||
CHECK(memcmp(buf, hexdata, buflen) == 0);
|
||||
|
||||
nvs::Page p2;
|
||||
@@ -2017,7 +2011,6 @@ TEST_CASE("Recovery from power-off during modification of blob present in old-fo
|
||||
size_t buflen = sizeof(hexdata);
|
||||
uint8_t buf[nvs::Page::CHUNK_MAX_SIZE];
|
||||
|
||||
|
||||
/* Power-off when blob was being written on the different page where its old version in old format
|
||||
* was present*/
|
||||
nvs::Page p;
|
||||
@@ -2046,7 +2039,7 @@ TEST_CASE("Recovery from power-off during modification of blob present in old-fo
|
||||
TEST_ESP_OK(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 3));
|
||||
TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
|
||||
|
||||
TEST_ESP_OK( nvs_get_blob(handle, "singlepage", buf, &buflen));
|
||||
TEST_ESP_OK(nvs_get_blob(handle, "singlepage", buf, &buflen));
|
||||
CHECK(memcmp(buf, hexdata, buflen) == 0);
|
||||
|
||||
nvs::Page p3;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -9,16 +9,15 @@
|
||||
#include <cstring>
|
||||
#include "nvs_internal.h"
|
||||
|
||||
namespace nvs
|
||||
{
|
||||
namespace nvs {
|
||||
|
||||
Page::Page() : mPartition(nullptr) { }
|
||||
|
||||
uint32_t Page::Header::calculateCrc32()
|
||||
{
|
||||
return esp_rom_crc32_le(0xffffffff,
|
||||
reinterpret_cast<uint8_t*>(this) + offsetof(Header, mSeqNumber),
|
||||
offsetof(Header, mCrc32) - offsetof(Header, mSeqNumber));
|
||||
reinterpret_cast<uint8_t*>(this) + offsetof(Header, mSeqNumber),
|
||||
offsetof(Header, mCrc32) - offsetof(Header, mSeqNumber));
|
||||
}
|
||||
|
||||
esp_err_t Page::load(Partition *partition, uint32_t sectorNumber)
|
||||
@@ -45,7 +44,9 @@ esp_err_t Page::load(Partition *partition, uint32_t sectorNumber)
|
||||
const int BLOCK_SIZE = 128;
|
||||
uint32_t* block = new (std::nothrow) uint32_t[BLOCK_SIZE];
|
||||
|
||||
if (!block) return ESP_ERR_NO_MEM;
|
||||
if (!block) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < SPI_FLASH_SEC_SIZE; i += 4 * BLOCK_SIZE) {
|
||||
rc = mPartition->read_raw(mBaseAddress + i, block, 4 * BLOCK_SIZE);
|
||||
@@ -66,7 +67,7 @@ esp_err_t Page::load(Partition *partition, uint32_t sectorNumber)
|
||||
} else {
|
||||
mState = header.mState;
|
||||
mSeqNumber = header.mSeqNumber;
|
||||
if(header.mVersion < NVS_VERSION) {
|
||||
if (header.mVersion < NVS_VERSION) {
|
||||
return ESP_ERR_NVS_NEW_VERSION_FOUND;
|
||||
} else {
|
||||
mVersion = header.mVersion;
|
||||
@@ -91,7 +92,7 @@ esp_err_t Page::load(Partition *partition, uint32_t sectorNumber)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t Page::writeEntry(const Item& item)
|
||||
esp_err_t Page::writeEntry(const Item &item)
|
||||
{
|
||||
uint32_t phyAddr;
|
||||
esp_err_t err = getEntryAddress(mNextFreeEntry, &phyAddr);
|
||||
@@ -100,7 +101,6 @@ esp_err_t Page::writeEntry(const Item& item)
|
||||
}
|
||||
err = mPartition->write(phyAddr, &item, sizeof(item));
|
||||
|
||||
|
||||
if (err != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
return err;
|
||||
@@ -189,7 +189,7 @@ esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, c
|
||||
|
||||
// primitive types should fit into one entry
|
||||
NVS_ASSERT_OR_RETURN(totalSize == ENTRY_SIZE ||
|
||||
isVariableLengthType(datatype), ESP_ERR_NVS_VALUE_TOO_LONG);
|
||||
isVariableLengthType(datatype), ESP_ERR_NVS_VALUE_TOO_LONG);
|
||||
|
||||
if (mNextFreeEntry == INVALID_ENTRY || mNextFreeEntry + entriesCount > ENTRY_COUNT) {
|
||||
// page will not fit this amount of data
|
||||
@@ -282,12 +282,12 @@ esp_err_t Page::readItem(uint8_t nsIndex, ItemType datatype, const char* key, vo
|
||||
return rc;
|
||||
}
|
||||
size_t willCopy = ENTRY_SIZE;
|
||||
willCopy = (left < willCopy)?left:willCopy;
|
||||
willCopy = (left < willCopy) ? left : willCopy;
|
||||
memcpy(dst, ditem.rawData, willCopy);
|
||||
left -= willCopy;
|
||||
dst += willCopy;
|
||||
}
|
||||
if (Item::calculateCrc32(reinterpret_cast<uint8_t*>(data), item.varLength.dataSize) != item.varLength.dataCrc32) {
|
||||
if (Item::calculateCrc32(reinterpret_cast<uint8_t * >(data), item.varLength.dataSize) != item.varLength.dataCrc32) {
|
||||
rc = eraseEntryAndSpan(index);
|
||||
if (rc != ESP_OK) {
|
||||
return rc;
|
||||
@@ -335,14 +335,14 @@ esp_err_t Page::cmpItem(uint8_t nsIndex, ItemType datatype, const char* key, con
|
||||
return rc;
|
||||
}
|
||||
size_t willCopy = ENTRY_SIZE;
|
||||
willCopy = (left < willCopy)?left:willCopy;
|
||||
willCopy = (left < willCopy) ? left : willCopy;
|
||||
if (memcmp(dst, ditem.rawData, willCopy)) {
|
||||
return ESP_ERR_NVS_CONTENT_DIFFERS;
|
||||
}
|
||||
left -= willCopy;
|
||||
dst += willCopy;
|
||||
}
|
||||
if (Item::calculateCrc32(reinterpret_cast<const uint8_t*>(data), item.varLength.dataSize) != item.varLength.dataCrc32) {
|
||||
if (Item::calculateCrc32(reinterpret_cast<const uint8_t * >(data), item.varLength.dataSize) != item.varLength.dataCrc32) {
|
||||
return ESP_ERR_NVS_NOT_FOUND;
|
||||
}
|
||||
|
||||
@@ -385,7 +385,7 @@ esp_err_t Page::eraseEntryAndSpan(size_t index)
|
||||
if (rc != ESP_OK) {
|
||||
return rc;
|
||||
}
|
||||
if (item.calculateCrc32() != item.crc32) {
|
||||
if (!item.checkHeaderConsistency(index)) {
|
||||
mHashList.erase(index);
|
||||
rc = alterEntryState(index, EntryState::ERASED);
|
||||
--mUsedEntryCount;
|
||||
@@ -459,7 +459,7 @@ esp_err_t Page::updateFirstUsedEntry(size_t index, size_t span)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t Page::copyItems(Page& other)
|
||||
esp_err_t Page::copyItems(Page &other)
|
||||
{
|
||||
if (mFirstUsedEntry == INVALID_ENTRY) {
|
||||
return ESP_ERR_NVS_NOT_FOUND;
|
||||
@@ -507,7 +507,10 @@ esp_err_t Page::copyItems(Page& other)
|
||||
NVS_ASSERT_OR_RETURN(end <= ENTRY_COUNT, ESP_FAIL);
|
||||
|
||||
for (size_t i = readEntryIndex + 1; i < end; ++i) {
|
||||
readEntry(i, entry);
|
||||
err = readEntry(i, entry);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
err = other.writeEntry(entry);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
@@ -526,7 +529,7 @@ esp_err_t Page::mLoadEntryTable()
|
||||
mState == PageState::FULL ||
|
||||
mState == PageState::FREEING) {
|
||||
auto rc = mPartition->read_raw(mBaseAddress + ENTRY_TABLE_OFFSET, mEntryTable.data(),
|
||||
mEntryTable.byteSize());
|
||||
mEntryTable.byteSize());
|
||||
if (rc != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
return rc;
|
||||
@@ -598,8 +601,7 @@ esp_err_t Page::mLoadEntryTable()
|
||||
--mUsedEntryCount;
|
||||
}
|
||||
++mErasedEntryCount;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -641,7 +643,7 @@ esp_err_t Page::mLoadEntryTable()
|
||||
return err;
|
||||
}
|
||||
|
||||
if (item.crc32 != item.calculateCrc32()) {
|
||||
if (!item.checkHeaderConsistency(i)) {
|
||||
err = eraseEntryAndSpan(i);
|
||||
if (err != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
@@ -721,7 +723,7 @@ esp_err_t Page::mLoadEntryTable()
|
||||
return err;
|
||||
}
|
||||
|
||||
if (item.crc32 != item.calculateCrc32()) {
|
||||
if (!item.checkHeaderConsistency(i)) {
|
||||
err = eraseEntryAndSpan(i);
|
||||
if (err != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
@@ -761,7 +763,6 @@ esp_err_t Page::mLoadEntryTable()
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t Page::initialize()
|
||||
{
|
||||
NVS_ASSERT_OR_RETURN(mState == PageState::UNINITIALIZED, ESP_FAIL);
|
||||
@@ -793,7 +794,7 @@ esp_err_t Page::alterEntryState(size_t index, EntryState state)
|
||||
size_t wordToWrite = mEntryTable.getWordIndex(index);
|
||||
uint32_t word = mEntryTable.data()[wordToWrite];
|
||||
err = mPartition->write_raw(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast<uint32_t>(wordToWrite) * 4,
|
||||
&word, sizeof(word));
|
||||
&word, sizeof(word));
|
||||
if (err != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
return err;
|
||||
@@ -809,7 +810,7 @@ esp_err_t Page::alterEntryRangeState(size_t begin, size_t end, EntryState state)
|
||||
esp_err_t err;
|
||||
for (ptrdiff_t i = end - 1; i >= static_cast<ptrdiff_t>(begin); --i) {
|
||||
err = mEntryTable.set(i, state);
|
||||
if (err != ESP_OK){
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
size_t nextWordIndex;
|
||||
@@ -821,7 +822,7 @@ esp_err_t Page::alterEntryRangeState(size_t begin, size_t end, EntryState state)
|
||||
if (nextWordIndex != wordIndex) {
|
||||
uint32_t word = mEntryTable.data()[wordIndex];
|
||||
auto rc = mPartition->write_raw(mBaseAddress + ENTRY_TABLE_OFFSET + static_cast<uint32_t>(wordIndex) * 4,
|
||||
&word, 4);
|
||||
&word, 4);
|
||||
if (rc != ESP_OK) {
|
||||
return rc;
|
||||
}
|
||||
@@ -843,7 +844,7 @@ esp_err_t Page::alterPageState(PageState state)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t Page::readEntry(size_t index, Item& dst) const
|
||||
esp_err_t Page::readEntry(size_t index, Item &dst) const
|
||||
{
|
||||
uint32_t phyAddr;
|
||||
esp_err_t rc = getEntryAddress(index, &phyAddr);
|
||||
@@ -857,7 +858,7 @@ esp_err_t Page::readEntry(size_t index, Item& dst) const
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, size_t &itemIndex, Item& item, uint8_t chunkIdx, VerOffset chunkStart)
|
||||
esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, size_t &itemIndex, Item &item, uint8_t chunkIdx, VerOffset chunkStart)
|
||||
{
|
||||
if (mState == PageState::CORRUPT || mState == PageState::INVALID || mState == PageState::UNINITIALIZED) {
|
||||
return ESP_ERR_NVS_NOT_FOUND;
|
||||
@@ -909,8 +910,7 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, si
|
||||
return rc;
|
||||
}
|
||||
|
||||
auto crc32 = item.calculateCrc32();
|
||||
if (item.crc32 != crc32) {
|
||||
if (!item.checkHeaderConsistency(i)) {
|
||||
rc = eraseEntryAndSpan(i);
|
||||
if (rc != ESP_OK) {
|
||||
mState = PageState::INVALID;
|
||||
@@ -974,7 +974,6 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, si
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (datatype != ItemType::ANY && item.datatype != datatype) {
|
||||
if (key == nullptr && nsIndex == NS_ANY && chunkIdx == CHUNK_ANY) {
|
||||
continue; // continue for bruteforce search on blob indices.
|
||||
@@ -991,7 +990,7 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, si
|
||||
return ESP_ERR_NVS_NOT_FOUND;
|
||||
}
|
||||
|
||||
esp_err_t Page::getSeqNumber(uint32_t& seqNumber) const
|
||||
esp_err_t Page::getSeqNumber(uint32_t &seqNumber) const
|
||||
{
|
||||
if (mState != PageState::UNINITIALIZED && mState != PageState::INVALID && mState != PageState::CORRUPT) {
|
||||
seqNumber = mSeqNumber;
|
||||
@@ -1000,7 +999,6 @@ esp_err_t Page::getSeqNumber(uint32_t& seqNumber) const
|
||||
return ESP_ERR_NVS_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t Page::setSeqNumber(uint32_t seqNumber)
|
||||
{
|
||||
if (mState != PageState::UNINITIALIZED) {
|
||||
@@ -1058,40 +1056,41 @@ size_t Page::getVarDataTailroom() const
|
||||
} else if (mState == PageState::FULL) {
|
||||
return 0;
|
||||
}
|
||||
/* Skip one entry for blob data item precessing the data */
|
||||
return ((mNextFreeEntry < (ENTRY_COUNT-1)) ? ((ENTRY_COUNT - mNextFreeEntry - 1) * ENTRY_SIZE): 0);
|
||||
/* Skip one entry for blob data item processing the data */
|
||||
return ((mNextFreeEntry < (ENTRY_COUNT - 1)) ? ((ENTRY_COUNT - mNextFreeEntry - 1) * ENTRY_SIZE) : 0);
|
||||
}
|
||||
|
||||
const char* Page::pageStateToName(PageState ps)
|
||||
{
|
||||
switch (ps) {
|
||||
case PageState::CORRUPT:
|
||||
return "CORRUPT";
|
||||
case PageState::CORRUPT:
|
||||
return "CORRUPT";
|
||||
|
||||
case PageState::ACTIVE:
|
||||
return "ACTIVE";
|
||||
case PageState::ACTIVE:
|
||||
return "ACTIVE";
|
||||
|
||||
case PageState::FREEING:
|
||||
return "FREEING";
|
||||
case PageState::FREEING:
|
||||
return "FREEING";
|
||||
|
||||
case PageState::FULL:
|
||||
return "FULL";
|
||||
case PageState::FULL:
|
||||
return "FULL";
|
||||
|
||||
case PageState::INVALID:
|
||||
return "INVALID";
|
||||
case PageState::INVALID:
|
||||
return "INVALID";
|
||||
|
||||
case PageState::UNINITIALIZED:
|
||||
return "UNINITIALIZED";
|
||||
case PageState::UNINITIALIZED:
|
||||
return "UNINITIALIZED";
|
||||
|
||||
default:
|
||||
assert(0 && "invalid state value");
|
||||
return "";
|
||||
default:
|
||||
assert(0 && "invalid state value");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void Page::debugDump() const
|
||||
{
|
||||
printf("state=%x (%s) addr=%x seq=%d\nfirstUsed=%d nextFree=%d used=%d erased=%d\n", (uint32_t) mState, pageStateToName(mState), mBaseAddress, mSeqNumber, static_cast<int>(mFirstUsedEntry), static_cast<int>(mNextFreeEntry), mUsedEntryCount, mErasedEntryCount);
|
||||
printf("state=%x (%s) addr=%x seq=%d\nfirstUsed=%d nextFree=%d used=%d erased=%d\n",
|
||||
(uint32_t) mState, pageStateToName(mState), mBaseAddress, mSeqNumber, static_cast<int>(mFirstUsedEntry), static_cast<int>(mNextFreeEntry), mUsedEntryCount, mErasedEntryCount);
|
||||
size_t skip = 0;
|
||||
for (size_t i = 0; i < ENTRY_COUNT; ++i) {
|
||||
printf("%3d: ", static_cast<int>(i));
|
||||
@@ -1108,7 +1107,9 @@ void Page::debugDump() const
|
||||
Item item;
|
||||
readEntry(i, item);
|
||||
if (skip == 0) {
|
||||
printf("W ns=%2u type=%2u span=%3u key=\"%s\" chunkIdx=%d len=%d\n", item.nsIndex, static_cast<unsigned>(item.datatype), item.span, item.key, item.chunkIndex, (item.span != 1)?((int)item.varLength.dataSize):-1);
|
||||
printf("W ns=%2u type=%2u span=%3u key=\"%s\" chunkIdx=%d len=%d\n",
|
||||
item.nsIndex, static_cast<unsigned>(item.datatype), item.span, item.key, item.chunkIndex, (item.span != 1)?((int)item.varLength.dataSize):-1);
|
||||
|
||||
if (item.span > 0 && item.span <= ENTRY_COUNT - i) {
|
||||
skip = item.span - 1;
|
||||
} else {
|
||||
@@ -1129,24 +1130,24 @@ esp_err_t Page::calcEntries(nvs_stats_t &nvsStats)
|
||||
nvsStats.total_entries += ENTRY_COUNT;
|
||||
|
||||
switch (mState) {
|
||||
case PageState::UNINITIALIZED:
|
||||
case PageState::CORRUPT:
|
||||
nvsStats.free_entries += ENTRY_COUNT;
|
||||
break;
|
||||
case PageState::UNINITIALIZED:
|
||||
case PageState::CORRUPT:
|
||||
nvsStats.free_entries += ENTRY_COUNT;
|
||||
break;
|
||||
|
||||
case PageState::FULL:
|
||||
case PageState::ACTIVE:
|
||||
nvsStats.used_entries += mUsedEntryCount;
|
||||
nvsStats.free_entries += ENTRY_COUNT - mUsedEntryCount; // it's equivalent free + erase entries.
|
||||
break;
|
||||
case PageState::FULL:
|
||||
case PageState::ACTIVE:
|
||||
nvsStats.used_entries += mUsedEntryCount;
|
||||
nvsStats.free_entries += ENTRY_COUNT - mUsedEntryCount; // it's equivalent free + erase entries.
|
||||
break;
|
||||
|
||||
case PageState::INVALID:
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
break;
|
||||
case PageState::INVALID:
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false && "Unhandled state");
|
||||
break;
|
||||
default:
|
||||
assert(false && "Unhandled state");
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@@ -1,28 +1,22 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "nvs_types.hpp"
|
||||
|
||||
#include "nvs_page.hpp"
|
||||
#include "esp_log.h"
|
||||
#include "esp_rom_crc.h"
|
||||
|
||||
namespace nvs
|
||||
{
|
||||
#define TAG "nvs"
|
||||
|
||||
namespace nvs {
|
||||
uint32_t Item::calculateCrc32() const
|
||||
{
|
||||
uint32_t result = 0xffffffff;
|
||||
const uint8_t* p = reinterpret_cast<const uint8_t*>(this);
|
||||
result = esp_rom_crc32_le(result, p + offsetof(Item, nsIndex),
|
||||
offsetof(Item, crc32) - offsetof(Item, nsIndex));
|
||||
offsetof(Item, crc32) - offsetof(Item, nsIndex));
|
||||
result = esp_rom_crc32_le(result, p + offsetof(Item, key), sizeof(key));
|
||||
result = esp_rom_crc32_le(result, p + offsetof(Item, data), sizeof(data));
|
||||
return result;
|
||||
@@ -33,7 +27,7 @@ uint32_t Item::calculateCrc32WithoutValue() const
|
||||
uint32_t result = 0xffffffff;
|
||||
const uint8_t* p = reinterpret_cast<const uint8_t*>(this);
|
||||
result = esp_rom_crc32_le(result, p + offsetof(Item, nsIndex),
|
||||
offsetof(Item, datatype) - offsetof(Item, nsIndex));
|
||||
offsetof(Item, datatype) - offsetof(Item, nsIndex));
|
||||
result = esp_rom_crc32_le(result, p + offsetof(Item, key), sizeof(key));
|
||||
result = esp_rom_crc32_le(result, p + offsetof(Item, chunkIndex), sizeof(chunkIndex));
|
||||
return result;
|
||||
@@ -46,4 +40,114 @@ uint32_t Item::calculateCrc32(const uint8_t* data, size_t size)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Item::checkHeaderConsistency(const uint8_t entryIndex) const
|
||||
{
|
||||
// calculate and check the crc32
|
||||
if (crc32 != calculateCrc32()) {
|
||||
ESP_LOGD(TAG, "CRC32 mismatch for entry %d", entryIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
// validate the datatype and check the rest of the header fields
|
||||
switch (datatype) {
|
||||
// Entries occupying just one entry
|
||||
case ItemType::U8:
|
||||
case ItemType::I8:
|
||||
case ItemType::U16:
|
||||
case ItemType::I16:
|
||||
case ItemType::U32:
|
||||
case ItemType::I32:
|
||||
case ItemType::U64:
|
||||
case ItemType::I64: {
|
||||
if (span != 1) {
|
||||
ESP_LOGD(TAG, "Invalid span %u for datatype %#04x", (unsigned int)span, (unsigned int)datatype);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Special case for BLOB_IDX
|
||||
case ItemType::BLOB_IDX: {
|
||||
// span must be 1
|
||||
if (span != 1) {
|
||||
ESP_LOGD(TAG, "Invalid span %u for BLOB_IDX", (unsigned int)span);
|
||||
return false;
|
||||
}
|
||||
|
||||
// chunkIndex must be CHUNK_ANY
|
||||
if (chunkIndex != CHUNK_ANY) {
|
||||
ESP_LOGD(TAG, "Invalid chunk index %u for BLOB_IDX", (unsigned int)chunkIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check maximum data length
|
||||
// the maximal data length is determined by:
|
||||
// maximum number of chunks. Chunks are stored in uin8_t, but are logically divided into two "VerOffset" ranges of values (0 based and 128 based)
|
||||
// maximum theoretical number of entries in the chunk (Page::ENTRY_COUNT - 1) and the number of bytes entry can store (Page::ENTRY_SIZE)
|
||||
const uint32_t maxDataSize = (uint32_t)((UINT8_MAX / 2) * (Page::ENTRY_COUNT - 1) * Page::ENTRY_SIZE);
|
||||
if (blobIndex.dataSize > maxDataSize) {
|
||||
ESP_LOGD(TAG, "Data size %u bytes exceeds maximum possible size %u bytes for BLOB_IDX", (unsigned int)blobIndex.dataSize, (unsigned int)maxDataSize);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Entries with variable length data
|
||||
case ItemType::SZ:
|
||||
case ItemType::BLOB:
|
||||
case ItemType::BLOB_DATA: {
|
||||
uint16_t maxAvailableVDataSize;
|
||||
uint8_t maxAvailablePageSpan;
|
||||
uint8_t spanCalcFromLen;
|
||||
|
||||
// for BLOB_DATA, chunkIndex must NOT be CHUNK_ANY as this value is used to search ALL chunks in findItem
|
||||
if (datatype == ItemType::BLOB_DATA) {
|
||||
// chunkIndex must not be CHUNK_ANY
|
||||
if (chunkIndex == CHUNK_ANY) {
|
||||
ESP_LOGD(TAG, "Invalid chunk index %u for BLOB_DATA", (unsigned int)chunkIndex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// variable length and span checks
|
||||
|
||||
// based on the entryIndex determine the maximum variable length capacity in bytes to the end of the page
|
||||
maxAvailableVDataSize = ((Page::ENTRY_COUNT - entryIndex) - 1) * Page::ENTRY_SIZE;
|
||||
|
||||
// check if the variable data length is not exceeding the maximum capacity available till the end of the page
|
||||
if (varLength.dataSize > maxAvailableVDataSize) {
|
||||
ESP_LOGD(TAG, "Variable data length %u bytes exceeds page boundary. Maximum calculated from the current entry position within page is %u bytes for datatype %#04x ", (unsigned int)varLength.dataSize, (unsigned int)maxAvailableVDataSize, (unsigned int)datatype);
|
||||
return false;
|
||||
}
|
||||
|
||||
// based on the entryIndex determine the maximum possible span up to the end of the page
|
||||
maxAvailablePageSpan = Page::ENTRY_COUNT - entryIndex;
|
||||
|
||||
// this check ensures no data is read beyond the end of the page
|
||||
if (span > maxAvailablePageSpan) {
|
||||
ESP_LOGD(TAG, "Span %u exceeds page boundary. Maximum calculated from the current entry position within page is %u for datatype %#04x ", (unsigned int)span, (unsigned int)maxAvailablePageSpan, (unsigned int)datatype);
|
||||
return false;
|
||||
}
|
||||
|
||||
// here we have both span and varLength.dataSize within the page boundary. Check if these values are consistent
|
||||
spanCalcFromLen = (uint8_t)(((size_t) varLength.dataSize + Page::ENTRY_SIZE - 1) / Page::ENTRY_SIZE);
|
||||
spanCalcFromLen ++; // add overhead entry
|
||||
|
||||
// this check ensures that the span is equal to the number of entries required to store the data plus the overhead entry
|
||||
if (span != spanCalcFromLen) {
|
||||
ESP_LOGD(TAG, "Span %i does not match span %u calculated from variable data length %u bytes for datatype %#04x", (unsigned int)span, (unsigned int)spanCalcFromLen, (unsigned int)varLength.dataSize, (unsigned int)datatype);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Invalid datatype
|
||||
default: {
|
||||
ESP_LOGD(TAG, "Invalid datatype %#04x", (unsigned int)datatype);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace nvs
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -108,6 +108,14 @@ public:
|
||||
dst = *reinterpret_cast<T*>(data);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
// Returns true if item's header:
|
||||
// crc32 matches the calculated crc32
|
||||
// and datatype is one of the supported types
|
||||
// and span is within the allowed range for the datatype and below the maximum calculated from the entryIndex
|
||||
//
|
||||
// Parameter entryIndex is used to calculate the maximum span for the given entry
|
||||
bool checkHeaderConsistency(const uint8_t entryIndex) const;
|
||||
};
|
||||
|
||||
} // namespace nvs
|
||||
|
@@ -719,7 +719,6 @@ components/nvs_flash/src/nvs_partition.cpp
|
||||
components/nvs_flash/src/nvs_partition_lookup.cpp
|
||||
components/nvs_flash/src/nvs_partition_lookup.hpp
|
||||
components/nvs_flash/src/nvs_test_api.h
|
||||
components/nvs_flash/src/nvs_types.cpp
|
||||
components/nvs_flash/src/partition.hpp
|
||||
components/nvs_flash/test/test_nvs.c
|
||||
components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp
|
||||
|
Reference in New Issue
Block a user