@@ -250,33 +250,19 @@ esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, c
250250 return ESP_OK;
251251}
252252
253- esp_err_t Page::readItem (uint8_t nsIndex, ItemType datatype, const char * key, void * data, size_t dataSize, uint8_t chunkIdx, VerOffset chunkStart)
253+ // Reads the data entries of the variable length item.
254+ // The metadata entry is already read in the item object.
255+ // index is the index of the metadata entry on the page.
256+ // data is pointer to the buffer where the data will be copied to. It has to be at least
257+ // item.varLength.dataSize bytes long.
258+ // The function returns ESP_OK if the data was read successfully, or an error code if there was an error.
259+ esp_err_t Page::readVariableLengthItemData (const Item& item, const size_t index, void * data)
254260{
255- size_t index = 0 ;
256- Item item;
257-
258261 if (mState == PageState::INVALID) {
259262 return ESP_ERR_NVS_INVALID_STATE;
260263 }
261264
262- esp_err_t rc = findItem (nsIndex, datatype, key, index, item, chunkIdx, chunkStart);
263- if (rc != ESP_OK) {
264- return rc;
265- }
266-
267- if (!isVariableLengthType (datatype)) {
268- if (dataSize != getAlignmentForType (datatype)) {
269- return ESP_ERR_NVS_TYPE_MISMATCH;
270- }
271-
272- memcpy (data, item.data , dataSize);
273- return ESP_OK;
274- }
275-
276- if (dataSize < static_cast <size_t >(item.varLength .dataSize )) {
277- return ESP_ERR_NVS_INVALID_LENGTH;
278- }
279-
265+ esp_err_t rc;
280266 uint8_t * dst = reinterpret_cast <uint8_t *>(data);
281267 size_t left = item.varLength .dataSize ;
282268 for (size_t i = index + 1 ; i < index + item.span ; ++i) {
@@ -301,6 +287,36 @@ esp_err_t Page::readItem(uint8_t nsIndex, ItemType datatype, const char* key, vo
301287 return ESP_OK;
302288}
303289
290+ esp_err_t Page::readItem (uint8_t nsIndex, ItemType datatype, const char * key, void * data, size_t dataSize, uint8_t chunkIdx, VerOffset chunkStart)
291+ {
292+ size_t index = 0 ;
293+ Item item;
294+
295+ if (mState == PageState::INVALID) {
296+ return ESP_ERR_NVS_INVALID_STATE;
297+ }
298+
299+ esp_err_t rc = findItem (nsIndex, datatype, key, index, item, chunkIdx, chunkStart);
300+ if (rc != ESP_OK) {
301+ return rc;
302+ }
303+
304+ if (!isVariableLengthType (datatype)) {
305+ if (dataSize != getAlignmentForType (datatype)) {
306+ return ESP_ERR_NVS_TYPE_MISMATCH;
307+ }
308+
309+ memcpy (data, item.data , dataSize);
310+ return ESP_OK;
311+ }
312+
313+ if (dataSize < static_cast <size_t >(item.varLength .dataSize )) {
314+ return ESP_ERR_NVS_INVALID_LENGTH;
315+ }
316+
317+ return readVariableLengthItemData (item, index, data);
318+ }
319+
304320esp_err_t Page::cmpItem (uint8_t nsIndex, ItemType datatype, const char * key, const void * data, size_t dataSize, uint8_t chunkIdx, VerOffset chunkStart)
305321{
306322 size_t index = 0 ;
@@ -330,9 +346,23 @@ esp_err_t Page::cmpItem(uint8_t nsIndex, ItemType datatype, const char* key, con
330346 return ESP_ERR_NVS_INVALID_LENGTH;
331347 }
332348
349+ // We have metadata of the variable length data chunk. It contains the length of the data and the crc32.
350+ // As a first step we can calculate the crc32 of the data buffer to be compared with the crc32 of the item in the flash.
351+ // If they are not equal, immediately return ESP_ERR_NVS_CONTENT_DIFFERS.
352+ // If they are equal, to avoid crc32 collision false positive, we will read the data from the flash entry by entry and compare
353+ // it with the respective chunk of input data buffer. The crc32 of the data read from the flash will be calculated on the fly.
354+ // At the end, we will compare the crc32 of the data read from the flash with the crc32 of the metadata item in the flash to make sure
355+ // that the data in the flash is not corrupted.
356+ if (Item::calculateCrc32 (reinterpret_cast <const uint8_t * >(data), item.varLength .dataSize ) != item.varLength .dataCrc32 ) {
357+ return ESP_ERR_NVS_CONTENT_DIFFERS;
358+ }
359+
333360 const uint8_t * dst = reinterpret_cast <const uint8_t *>(data);
334361 size_t left = item.varLength .dataSize ;
335- for (size_t i = index + 1 ; i < index + item.span ; ++i) {
362+ uint32_t accumulatedCRC32;
363+ size_t initial_index = index + 1 ;
364+
365+ for (size_t i = initial_index; i < index + item.span ; ++i) {
336366 Item ditem;
337367 rc = readEntry (i, ditem);
338368 if (rc != ESP_OK) {
@@ -343,11 +373,18 @@ esp_err_t Page::cmpItem(uint8_t nsIndex, ItemType datatype, const char* key, con
343373 if (memcmp (dst, ditem.rawData , willCopy)) {
344374 return ESP_ERR_NVS_CONTENT_DIFFERS;
345375 }
376+
377+ // Calculate the crc32 of the actual ditem.rawData buffer. Do not pass accumulatedCRC32 in the first call.
378+ // In the first call, calculateCrc32 will use its default. In the subsequent calls, accumulatedCRC32 is the crc32 of the previous buffer.
379+ accumulatedCRC32 = Item::calculateCrc32 (ditem.rawData , willCopy, (i == initial_index) ? nullptr : &accumulatedCRC32);
380+
346381 left -= willCopy;
347382 dst += willCopy;
348383 }
349- if (Item::calculateCrc32 (reinterpret_cast <const uint8_t * >(data), item.varLength .dataSize ) != item.varLength .dataCrc32 ) {
350- return ESP_ERR_NVS_NOT_FOUND;
384+ // Check if the CRC32 calculated on the fly matches the variable length data CRC32 indicated in the metadata entry.
385+ // If they are not equal, it means the data in the flash is corrupt, we will return ESP_ERR_NVS_CONTENT_DIFFERS.
386+ if (accumulatedCRC32 != item.varLength .dataCrc32 ) {
387+ return ESP_ERR_NVS_CONTENT_DIFFERS;
351388 }
352389
353390 return ESP_OK;
0 commit comments