mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-08 22:31:01 +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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -575,7 +575,6 @@ TEST_CASE("nvs api tests", "[nvs]")
|
|||||||
const uint32_t NVS_FLASH_SECTOR_COUNT_MIN = 3;
|
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);)
|
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);
|
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) {
|
for (uint16_t i = NVS_FLASH_SECTOR; i < NVS_FLASH_SECTOR + NVS_FLASH_SECTOR_COUNT_MIN; ++i) {
|
||||||
TEMPORARILY_DISABLED(f.emu.erase(i);)
|
TEMPORARILY_DISABLED(f.emu.erase(i);)
|
||||||
@@ -748,8 +747,7 @@ TEST_CASE("nvs iterators tests", "[nvs]")
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
nvs_iterator_t it = nullptr;
|
nvs_iterator_t it = nullptr;
|
||||||
esp_err_t res = nvs_entry_find(part, name, type, &it);
|
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);
|
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,
|
CHECK(res == ESP_ERR_NVS_NOT_FOUND); // after finishing the loop or if no entry was found to begin with,
|
||||||
@@ -858,7 +856,6 @@ TEST_CASE("nvs iterators tests", "[nvs]")
|
|||||||
nvs_release_iterator(it);
|
nvs_release_iterator(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SECTION("Iterating over multiple pages works correctly") {
|
SECTION("Iterating over multiple pages works correctly") {
|
||||||
nvs_handle_t handle_3;
|
nvs_handle_t handle_3;
|
||||||
const char *name_3 = "namespace3";
|
const char *name_3 = "namespace3";
|
||||||
@@ -1123,8 +1120,7 @@ public:
|
|||||||
static_assert(nKeys == sizeof(values) / sizeof(values[0]), "");
|
static_assert(nKeys == sizeof(values) / sizeof(values[0]), "");
|
||||||
|
|
||||||
auto randomRead = [&](size_t index) -> esp_err_t {
|
auto randomRead = [&](size_t index) -> esp_err_t {
|
||||||
switch (types[index])
|
switch (types[index]) {
|
||||||
{
|
|
||||||
case nvs::ItemType::I32: {
|
case nvs::ItemType::I32: {
|
||||||
int32_t val;
|
int32_t val;
|
||||||
auto err = nvs_get_i32(handle, keys[index], &val);
|
auto err = nvs_get_i32(handle, keys[index], &val);
|
||||||
@@ -1204,8 +1200,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto randomWrite = [&](size_t index) -> esp_err_t {
|
auto randomWrite = [&](size_t index) -> esp_err_t {
|
||||||
switch (types[index])
|
switch (types[index]) {
|
||||||
{
|
|
||||||
case nvs::ItemType::I32: {
|
case nvs::ItemType::I32: {
|
||||||
int32_t val = static_cast<int32_t>(gen());
|
int32_t val = static_cast<int32_t>(gen());
|
||||||
|
|
||||||
@@ -1323,7 +1318,7 @@ public:
|
|||||||
return ESP_OK;
|
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 (index == 9) { /* This is only done for small-page blobs for now*/
|
||||||
if (len > smallBlobLen) {
|
if (len > smallBlobLen) {
|
||||||
@@ -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_open("LIGHT", NVS_READWRITE, &light_handle));
|
||||||
ESP_ERROR_CHECK(nvs_set_u8(light_handle, "RecordNum", number));
|
ESP_ERROR_CHECK(nvs_set_u8(light_handle, "RecordNum", number));
|
||||||
for (i = 0; i < number; ++i) {
|
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)));
|
ESP_ERROR_CHECK(nvs_set_blob(light_handle, key, data, sizeof(data)));
|
||||||
}
|
}
|
||||||
nvs_commit(light_handle);
|
nvs_commit(light_handle);
|
||||||
@@ -1415,7 +1410,7 @@ TEST_CASE("read/write failure (TW8406)", "[nvs]")
|
|||||||
REQUIRE(number == get_number);
|
REQUIRE(number == get_number);
|
||||||
for (i = 0; i < number; ++i) {
|
for (i = 0; i < number; ++i) {
|
||||||
char data[76] = {0};
|
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));
|
ESP_ERROR_CHECK(nvs_get_blob(light_handle, key, data, &data_len));
|
||||||
}
|
}
|
||||||
nvs_close(light_handle);
|
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;
|
const size_t blob_size = nvs::Page::CHUNK_MAX_SIZE;
|
||||||
uint8_t blob[blob_size] = {0};
|
uint8_t blob[blob_size] = {0};
|
||||||
PartitionEmulationFixture f(0, 8);
|
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;
|
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
|
// 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
|
// 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
|
// Fill third page
|
||||||
TEST_ESP_OK( nvs_set_blob(handle, "3a", blob, blob_size) );
|
TEST_ESP_OK(nvs_set_blob(handle, "3a", blob, blob_size));
|
||||||
TEST_ESP_OK( nvs_commit(handle) );
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
nvs_close(handle);
|
nvs_close(handle);
|
||||||
TEST_ESP_OK(nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME));
|
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
|
// first two pages are now full, third one is writable, last two are empty
|
||||||
// init should fail
|
// init should fail
|
||||||
TEST_ESP_ERR( nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 3),
|
TEST_ESP_ERR(nvs::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 3),
|
||||||
ESP_ERR_NVS_NO_FREE_PAGES );
|
ESP_ERR_NVS_NO_FREE_PAGES);
|
||||||
|
|
||||||
// in case this test fails, to not affect other tests
|
// in case this test fails, to not affect other tests
|
||||||
nvs_flash_deinit_partition(NVS_DEFAULT_PART_NAME);
|
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;
|
const size_t blob_size = nvs::Page::CHUNK_MAX_SIZE / 2;
|
||||||
uint8_t blob[blob_size] = {0};
|
uint8_t blob[blob_size] = {0};
|
||||||
PartitionEmulationFixture f(0, 3);
|
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;
|
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
|
// Fill first page
|
||||||
TEST_ESP_OK( nvs_set_blob(handle, "1a", blob, blob_size / 3) );
|
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, "1b", blob, blob_size));
|
||||||
// Fill second page
|
// 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));
|
||||||
TEST_ESP_OK( nvs_set_blob(handle, "2b", 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.
|
// 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_set_blob(handle, "3a", blob, 4));
|
||||||
TEST_ESP_OK( nvs_commit(handle) );
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
nvs_close(handle);
|
nvs_close(handle);
|
||||||
|
|
||||||
TEST_ESP_OK(nvs_flash_deinit_partition(f.part()->get_partition_name()));
|
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};
|
uint8_t blob4[blob_size] = { 0x33};
|
||||||
size_t read_size = blob_size;
|
size_t read_size = blob_size;
|
||||||
PartitionEmulationFixture f(0, 6);
|
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;
|
nvs_handle_t handle;
|
||||||
memset(blob, 0x11, blob_size);
|
memset(blob, 0x11, blob_size);
|
||||||
memset(blob2, 0x22, blob_size);
|
memset(blob2, 0x22, blob_size);
|
||||||
memset(blob3, 0x33, blob_size);
|
memset(blob3, 0x33, blob_size);
|
||||||
memset(blob4, 0x44, blob_size);
|
memset(blob4, 0x44, blob_size);
|
||||||
memset(blob_read, 0xff, blob_size);
|
memset(blob_read, 0xff, blob_size);
|
||||||
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, blob_size));
|
||||||
TEST_ESP_OK( nvs_set_blob(handle, "abc", blob2, 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", blob3, blob_size));
|
||||||
TEST_ESP_OK( nvs_set_blob(handle, "abc", blob4, 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_get_blob(handle, "abc", blob_read, &read_size));
|
||||||
CHECK(memcmp(blob4, blob_read, blob_size) == 0);
|
CHECK(memcmp(blob4, blob_read, blob_size) == 0);
|
||||||
TEST_ESP_OK( nvs_commit(handle) );
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
nvs_close(handle);
|
nvs_close(handle);
|
||||||
|
|
||||||
TEST_ESP_OK(nvs_flash_deinit_partition(f.part()->get_partition_name()));
|
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};
|
uint8_t blob_read[blob_size] = {0xff};
|
||||||
size_t read_size = blob_size;
|
size_t read_size = blob_size;
|
||||||
PartitionEmulationFixture f(0, 5);
|
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;
|
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, nvs::Page::CHUNK_MAX_SIZE / 2));
|
||||||
TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size));
|
TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, blob_size));
|
||||||
TEST_ESP_OK(nvs_get_blob(handle, "abc", blob_read, &read_size));
|
TEST_ESP_OK(nvs_get_blob(handle, "abc", blob_read, &read_size));
|
||||||
CHECK(memcmp(blob, blob_read, blob_size) == 0);
|
CHECK(memcmp(blob, blob_read, blob_size) == 0);
|
||||||
TEST_ESP_OK(nvs_commit(handle) );
|
TEST_ESP_OK(nvs_commit(handle));
|
||||||
nvs_close(handle);
|
nvs_close(handle);
|
||||||
|
|
||||||
TEST_ESP_OK(nvs_flash_deinit_partition(f.part()->get_partition_name()));
|
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};
|
uint8_t blob_read[blob_size] = {0xff};
|
||||||
size_t read_size = blob_size;
|
size_t read_size = blob_size;
|
||||||
PartitionEmulationFixture f(0, 5);
|
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;
|
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, blob_size));
|
||||||
TEST_ESP_OK(nvs_set_blob(handle, "abc", blob, nvs::Page::CHUNK_MAX_SIZE / 2));
|
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_set_blob(handle, "abc2", blob, blob_size));
|
||||||
TEST_ESP_OK(nvs_get_blob(handle, "abc", blob_read, &read_size));
|
TEST_ESP_OK(nvs_get_blob(handle, "abc", blob_read, &read_size));
|
||||||
CHECK(memcmp(blob, blob_read, nvs::Page::CHUNK_MAX_SIZE) == 0);
|
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);
|
nvs_close(handle);
|
||||||
|
|
||||||
TEST_ESP_OK(nvs_flash_deinit_partition(f.part()->get_partition_name()));
|
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.writeItem(1, nvs::ItemType::BLOB, "key", blob, sizeof(blob)));
|
||||||
|
|
||||||
|
|
||||||
TEST_ESP_OK(storage.init(0, 5));
|
TEST_ESP_OK(storage.init(0, 5));
|
||||||
/* Check that multi-page item is still available.**/
|
/* Check that multi-page item is still available.**/
|
||||||
TEST_ESP_OK(storage.readItem(1, nvs::ItemType::BLOB, "key", blob, sizeof(blob)));
|
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]")
|
TEST_CASE("nvs blob fragmentation test", "[nvs]")
|
||||||
{
|
{
|
||||||
PartitionEmulationFixture f(0, 4);
|
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;
|
const size_t BLOB_SIZE = 3500;
|
||||||
uint8_t *blob = (uint8_t *) malloc(BLOB_SIZE);
|
uint8_t *blob = (uint8_t *) malloc(BLOB_SIZE);
|
||||||
CHECK(blob != NULL);
|
CHECK(blob != NULL);
|
||||||
memset(blob, 0xEE, BLOB_SIZE);
|
memset(blob, 0xEE, BLOB_SIZE);
|
||||||
const uint32_t magic = 0xff33eaeb;
|
const uint32_t magic = 0xff33eaeb;
|
||||||
nvs_handle_t h;
|
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++) {
|
for (int i = 0; i < 128; i++) {
|
||||||
INFO("Iteration " << i << "...\n");
|
INFO("Iteration " << i << "...\n");
|
||||||
TEST_ESP_OK( nvs_set_u32(h, "magic", magic) );
|
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_blob(h, "blob", blob, BLOB_SIZE));
|
||||||
char seq_buf[16];
|
char seq_buf[16];
|
||||||
sprintf(seq_buf, "seq%d", i);
|
snprintf(seq_buf, sizeof(seq_buf), "seq%d", i);
|
||||||
TEST_ESP_OK( nvs_set_u32(h, seq_buf, i) );
|
TEST_ESP_OK(nvs_set_u32(h, seq_buf, i));
|
||||||
}
|
}
|
||||||
free(blob);
|
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*/
|
/* Four pages should fit roughly 12 blobs*/
|
||||||
for (uint8_t count = 1; count <= 12; count++) {
|
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)));
|
TEST_ESP_OK(storage.writeItem(1, nvs::ItemType::BLOB, nvs_key, blob, sizeof(blob)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t count = 13; count <= 20; count++) {
|
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);
|
TEST_ESP_ERR(storage.writeItem(1, nvs::ItemType::BLOB, nvs_key, blob, sizeof(blob)), ESP_ERR_NVS_NOT_ENOUGH_SPACE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1871,7 +1865,7 @@ TEST_CASE("monkey test with old-format blob present", "[nvs][monkey]")
|
|||||||
TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
|
TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
|
||||||
RandomTest test;
|
RandomTest test;
|
||||||
|
|
||||||
for ( uint8_t it = 0; it < 10; it++) {
|
for (uint8_t it = 0; it < 10; it++) {
|
||||||
size_t count = 200;
|
size_t count = 200;
|
||||||
|
|
||||||
/* Erase index and chunks for the blob with "singlepage" key */
|
/* Erase index and chunks for the blob with "singlepage" key */
|
||||||
@@ -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::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 3));
|
||||||
TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
|
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);
|
CHECK(memcmp(buf, hexdata, buflen) == 0);
|
||||||
|
|
||||||
nvs::Page p2;
|
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);
|
size_t buflen = sizeof(hexdata);
|
||||||
uint8_t buf[nvs::Page::CHUNK_MAX_SIZE];
|
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
|
/* Power-off when blob was being written on the different page where its old version in old format
|
||||||
* was present*/
|
* was present*/
|
||||||
nvs::Page p;
|
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::NVSPartitionManager::get_instance()->init_custom(f.part(), 0, 3));
|
||||||
TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle));
|
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);
|
CHECK(memcmp(buf, hexdata, buflen) == 0);
|
||||||
|
|
||||||
nvs::Page p3;
|
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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -9,8 +9,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "nvs_internal.h"
|
#include "nvs_internal.h"
|
||||||
|
|
||||||
namespace nvs
|
namespace nvs {
|
||||||
{
|
|
||||||
|
|
||||||
Page::Page() : mPartition(nullptr) { }
|
Page::Page() : mPartition(nullptr) { }
|
||||||
|
|
||||||
@@ -45,7 +44,9 @@ esp_err_t Page::load(Partition *partition, uint32_t sectorNumber)
|
|||||||
const int BLOCK_SIZE = 128;
|
const int BLOCK_SIZE = 128;
|
||||||
uint32_t* block = new (std::nothrow) uint32_t[BLOCK_SIZE];
|
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) {
|
for (uint32_t i = 0; i < SPI_FLASH_SEC_SIZE; i += 4 * BLOCK_SIZE) {
|
||||||
rc = mPartition->read_raw(mBaseAddress + i, block, 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 {
|
} else {
|
||||||
mState = header.mState;
|
mState = header.mState;
|
||||||
mSeqNumber = header.mSeqNumber;
|
mSeqNumber = header.mSeqNumber;
|
||||||
if(header.mVersion < NVS_VERSION) {
|
if (header.mVersion < NVS_VERSION) {
|
||||||
return ESP_ERR_NVS_NEW_VERSION_FOUND;
|
return ESP_ERR_NVS_NEW_VERSION_FOUND;
|
||||||
} else {
|
} else {
|
||||||
mVersion = header.mVersion;
|
mVersion = header.mVersion;
|
||||||
@@ -91,7 +92,7 @@ esp_err_t Page::load(Partition *partition, uint32_t sectorNumber)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t Page::writeEntry(const Item& item)
|
esp_err_t Page::writeEntry(const Item &item)
|
||||||
{
|
{
|
||||||
uint32_t phyAddr;
|
uint32_t phyAddr;
|
||||||
esp_err_t err = getEntryAddress(mNextFreeEntry, &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));
|
err = mPartition->write(phyAddr, &item, sizeof(item));
|
||||||
|
|
||||||
|
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
mState = PageState::INVALID;
|
mState = PageState::INVALID;
|
||||||
return err;
|
return err;
|
||||||
@@ -282,12 +282,12 @@ esp_err_t Page::readItem(uint8_t nsIndex, ItemType datatype, const char* key, vo
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
size_t willCopy = ENTRY_SIZE;
|
size_t willCopy = ENTRY_SIZE;
|
||||||
willCopy = (left < willCopy)?left:willCopy;
|
willCopy = (left < willCopy) ? left : willCopy;
|
||||||
memcpy(dst, ditem.rawData, willCopy);
|
memcpy(dst, ditem.rawData, willCopy);
|
||||||
left -= willCopy;
|
left -= willCopy;
|
||||||
dst += 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);
|
rc = eraseEntryAndSpan(index);
|
||||||
if (rc != ESP_OK) {
|
if (rc != ESP_OK) {
|
||||||
return rc;
|
return rc;
|
||||||
@@ -335,14 +335,14 @@ esp_err_t Page::cmpItem(uint8_t nsIndex, ItemType datatype, const char* key, con
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
size_t willCopy = ENTRY_SIZE;
|
size_t willCopy = ENTRY_SIZE;
|
||||||
willCopy = (left < willCopy)?left:willCopy;
|
willCopy = (left < willCopy) ? left : willCopy;
|
||||||
if (memcmp(dst, ditem.rawData, willCopy)) {
|
if (memcmp(dst, ditem.rawData, willCopy)) {
|
||||||
return ESP_ERR_NVS_CONTENT_DIFFERS;
|
return ESP_ERR_NVS_CONTENT_DIFFERS;
|
||||||
}
|
}
|
||||||
left -= willCopy;
|
left -= willCopy;
|
||||||
dst += 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;
|
return ESP_ERR_NVS_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,7 +385,7 @@ esp_err_t Page::eraseEntryAndSpan(size_t index)
|
|||||||
if (rc != ESP_OK) {
|
if (rc != ESP_OK) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
if (item.calculateCrc32() != item.crc32) {
|
if (!item.checkHeaderConsistency(index)) {
|
||||||
mHashList.erase(index);
|
mHashList.erase(index);
|
||||||
rc = alterEntryState(index, EntryState::ERASED);
|
rc = alterEntryState(index, EntryState::ERASED);
|
||||||
--mUsedEntryCount;
|
--mUsedEntryCount;
|
||||||
@@ -459,7 +459,7 @@ esp_err_t Page::updateFirstUsedEntry(size_t index, size_t span)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t Page::copyItems(Page& other)
|
esp_err_t Page::copyItems(Page &other)
|
||||||
{
|
{
|
||||||
if (mFirstUsedEntry == INVALID_ENTRY) {
|
if (mFirstUsedEntry == INVALID_ENTRY) {
|
||||||
return ESP_ERR_NVS_NOT_FOUND;
|
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);
|
NVS_ASSERT_OR_RETURN(end <= ENTRY_COUNT, ESP_FAIL);
|
||||||
|
|
||||||
for (size_t i = readEntryIndex + 1; i < end; ++i) {
|
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);
|
err = other.writeEntry(entry);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
return err;
|
return err;
|
||||||
@@ -598,8 +601,7 @@ esp_err_t Page::mLoadEntryTable()
|
|||||||
--mUsedEntryCount;
|
--mUsedEntryCount;
|
||||||
}
|
}
|
||||||
++mErasedEntryCount;
|
++mErasedEntryCount;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -641,7 +643,7 @@ esp_err_t Page::mLoadEntryTable()
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.crc32 != item.calculateCrc32()) {
|
if (!item.checkHeaderConsistency(i)) {
|
||||||
err = eraseEntryAndSpan(i);
|
err = eraseEntryAndSpan(i);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
mState = PageState::INVALID;
|
mState = PageState::INVALID;
|
||||||
@@ -721,7 +723,7 @@ esp_err_t Page::mLoadEntryTable()
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.crc32 != item.calculateCrc32()) {
|
if (!item.checkHeaderConsistency(i)) {
|
||||||
err = eraseEntryAndSpan(i);
|
err = eraseEntryAndSpan(i);
|
||||||
if (err != ESP_OK) {
|
if (err != ESP_OK) {
|
||||||
mState = PageState::INVALID;
|
mState = PageState::INVALID;
|
||||||
@@ -761,7 +763,6 @@ esp_err_t Page::mLoadEntryTable()
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
esp_err_t Page::initialize()
|
esp_err_t Page::initialize()
|
||||||
{
|
{
|
||||||
NVS_ASSERT_OR_RETURN(mState == PageState::UNINITIALIZED, ESP_FAIL);
|
NVS_ASSERT_OR_RETURN(mState == PageState::UNINITIALIZED, ESP_FAIL);
|
||||||
@@ -809,7 +810,7 @@ esp_err_t Page::alterEntryRangeState(size_t begin, size_t end, EntryState state)
|
|||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
for (ptrdiff_t i = end - 1; i >= static_cast<ptrdiff_t>(begin); --i) {
|
for (ptrdiff_t i = end - 1; i >= static_cast<ptrdiff_t>(begin); --i) {
|
||||||
err = mEntryTable.set(i, state);
|
err = mEntryTable.set(i, state);
|
||||||
if (err != ESP_OK){
|
if (err != ESP_OK) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
size_t nextWordIndex;
|
size_t nextWordIndex;
|
||||||
@@ -843,7 +844,7 @@ esp_err_t Page::alterPageState(PageState state)
|
|||||||
return ESP_OK;
|
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;
|
uint32_t phyAddr;
|
||||||
esp_err_t rc = getEntryAddress(index, &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;
|
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) {
|
if (mState == PageState::CORRUPT || mState == PageState::INVALID || mState == PageState::UNINITIALIZED) {
|
||||||
return ESP_ERR_NVS_NOT_FOUND;
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto crc32 = item.calculateCrc32();
|
if (!item.checkHeaderConsistency(i)) {
|
||||||
if (item.crc32 != crc32) {
|
|
||||||
rc = eraseEntryAndSpan(i);
|
rc = eraseEntryAndSpan(i);
|
||||||
if (rc != ESP_OK) {
|
if (rc != ESP_OK) {
|
||||||
mState = PageState::INVALID;
|
mState = PageState::INVALID;
|
||||||
@@ -974,7 +974,6 @@ esp_err_t Page::findItem(uint8_t nsIndex, ItemType datatype, const char* key, si
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (datatype != ItemType::ANY && item.datatype != datatype) {
|
if (datatype != ItemType::ANY && item.datatype != datatype) {
|
||||||
if (key == nullptr && nsIndex == NS_ANY && chunkIdx == CHUNK_ANY) {
|
if (key == nullptr && nsIndex == NS_ANY && chunkIdx == CHUNK_ANY) {
|
||||||
continue; // continue for bruteforce search on blob indices.
|
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;
|
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) {
|
if (mState != PageState::UNINITIALIZED && mState != PageState::INVALID && mState != PageState::CORRUPT) {
|
||||||
seqNumber = mSeqNumber;
|
seqNumber = mSeqNumber;
|
||||||
@@ -1000,7 +999,6 @@ esp_err_t Page::getSeqNumber(uint32_t& seqNumber) const
|
|||||||
return ESP_ERR_NVS_NOT_INITIALIZED;
|
return ESP_ERR_NVS_NOT_INITIALIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
esp_err_t Page::setSeqNumber(uint32_t seqNumber)
|
esp_err_t Page::setSeqNumber(uint32_t seqNumber)
|
||||||
{
|
{
|
||||||
if (mState != PageState::UNINITIALIZED) {
|
if (mState != PageState::UNINITIALIZED) {
|
||||||
@@ -1058,8 +1056,8 @@ size_t Page::getVarDataTailroom() const
|
|||||||
} else if (mState == PageState::FULL) {
|
} else if (mState == PageState::FULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Skip one entry for blob data item precessing the data */
|
/* Skip one entry for blob data item processing the data */
|
||||||
return ((mNextFreeEntry < (ENTRY_COUNT-1)) ? ((ENTRY_COUNT - mNextFreeEntry - 1) * ENTRY_SIZE): 0);
|
return ((mNextFreeEntry < (ENTRY_COUNT - 1)) ? ((ENTRY_COUNT - mNextFreeEntry - 1) * ENTRY_SIZE) : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* Page::pageStateToName(PageState ps)
|
const char* Page::pageStateToName(PageState ps)
|
||||||
@@ -1091,7 +1089,8 @@ const char* Page::pageStateToName(PageState ps)
|
|||||||
|
|
||||||
void Page::debugDump() const
|
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;
|
size_t skip = 0;
|
||||||
for (size_t i = 0; i < ENTRY_COUNT; ++i) {
|
for (size_t i = 0; i < ENTRY_COUNT; ++i) {
|
||||||
printf("%3d: ", static_cast<int>(i));
|
printf("%3d: ", static_cast<int>(i));
|
||||||
@@ -1108,7 +1107,9 @@ void Page::debugDump() const
|
|||||||
Item item;
|
Item item;
|
||||||
readEntry(i, item);
|
readEntry(i, item);
|
||||||
if (skip == 0) {
|
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) {
|
if (item.span > 0 && item.span <= ENTRY_COUNT - i) {
|
||||||
skip = item.span - 1;
|
skip = item.span - 1;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -1,22 +1,16 @@
|
|||||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
/*
|
||||||
//
|
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
*
|
||||||
// you may not use this file except in compliance with the License.
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
// 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.
|
|
||||||
#include "nvs_types.hpp"
|
#include "nvs_types.hpp"
|
||||||
|
#include "nvs_page.hpp"
|
||||||
|
#include "esp_log.h"
|
||||||
#include "esp_rom_crc.h"
|
#include "esp_rom_crc.h"
|
||||||
|
|
||||||
namespace nvs
|
#define TAG "nvs"
|
||||||
{
|
|
||||||
|
namespace nvs {
|
||||||
uint32_t Item::calculateCrc32() const
|
uint32_t Item::calculateCrc32() const
|
||||||
{
|
{
|
||||||
uint32_t result = 0xffffffff;
|
uint32_t result = 0xffffffff;
|
||||||
@@ -46,4 +40,114 @@ uint32_t Item::calculateCrc32(const uint8_t* data, size_t size)
|
|||||||
return result;
|
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
|
} // 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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@@ -108,6 +108,14 @@ public:
|
|||||||
dst = *reinterpret_cast<T*>(data);
|
dst = *reinterpret_cast<T*>(data);
|
||||||
return ESP_OK;
|
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
|
} // 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.cpp
|
||||||
components/nvs_flash/src/nvs_partition_lookup.hpp
|
components/nvs_flash/src/nvs_partition_lookup.hpp
|
||||||
components/nvs_flash/src/nvs_test_api.h
|
components/nvs_flash/src/nvs_test_api.h
|
||||||
components/nvs_flash/src/nvs_types.cpp
|
|
||||||
components/nvs_flash/src/partition.hpp
|
components/nvs_flash/src/partition.hpp
|
||||||
components/nvs_flash/test/test_nvs.c
|
components/nvs_flash/test/test_nvs.c
|
||||||
components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp
|
components/nvs_flash/test_nvs_host/esp_error_check_stub.cpp
|
||||||
|
Reference in New Issue
Block a user