in core/manifest/manifest_flash.c [1030:1162]
int manifest_flash_get_child_elements_info (const struct manifest_flash *manifest,
const struct hash_engine *hash, int entry, uint8_t type, uint8_t parent_type,
uint8_t child_type, size_t *child_len, int *child_count, int *first_entry)
{
uint8_t validate_hash[SHA512_HASH_LENGTH];
struct manifest_toc_entry toc_entry;
uint32_t entry_addr;
uint32_t hash_addr;
bool only_entry = ((child_len == NULL) && (child_count == NULL));
int status;
if ((manifest == NULL) || (hash == NULL) || (only_entry && (first_entry == NULL))) {
return MANIFEST_INVALID_ARGUMENT;
}
if (!manifest->state->manifest_valid) {
return MANIFEST_NO_MANIFEST;
}
if (child_len != NULL) {
*child_len = 0;
}
if (child_count != NULL) {
*child_count = 0;
}
if (first_entry != NULL) {
*first_entry = 0;
}
if (entry >= manifest->state->toc_header.entry_count) {
return 0;
}
entry_addr = manifest->addr + sizeof (struct manifest_header) +
sizeof (struct manifest_toc_header);
hash_addr = entry_addr +
((sizeof (struct manifest_toc_entry) + manifest->state->toc_hash_length) *
manifest->state->toc_header.entry_count);
/* Start hashing to verify the TOC contents. */
status = hash_start_new_hash (hash, manifest->state->toc_hash_type);
if (status != 0) {
return status;
}
status = hash->update (hash, (uint8_t*) &manifest->state->toc_header,
sizeof (struct manifest_toc_header));
if (status != 0) {
goto error;
}
/* Hash the TOC data before the first entry that will be read. */
status = flash_hash_update_contents (manifest->flash, entry_addr,
sizeof (struct manifest_toc_entry) * entry, hash);
if (status != 0) {
goto error;
}
entry_addr += (sizeof (struct manifest_toc_entry) * entry);
for (; entry < manifest->state->toc_header.entry_count;
++entry, entry_addr += sizeof (struct manifest_toc_entry)) {
status = manifest->flash->read (manifest->flash, entry_addr, (uint8_t*) &toc_entry,
sizeof (struct manifest_toc_entry));
if (status != 0) {
goto error;
}
status = hash->update (hash, (uint8_t*) &toc_entry, sizeof (struct manifest_toc_entry));
if (status != 0) {
goto error;
}
if ((toc_entry.parent == parent_type) || (toc_entry.type_id == parent_type)) {
if (only_entry) {
status = MANIFEST_CHILD_NOT_FOUND;
goto error;
}
entry_addr += sizeof (struct manifest_toc_entry);
break;
}
if ((toc_entry.parent == type) && (toc_entry.type_id == child_type)) {
if ((first_entry != NULL) && (*first_entry == 0)) {
*first_entry = entry;
if (only_entry) {
entry_addr += sizeof (struct manifest_toc_entry);
break;
}
}
if (child_count != NULL) {
*child_count = *child_count + 1;
}
if (child_len != NULL) {
*child_len = *child_len + toc_entry.length;
}
}
}
if (only_entry && (*first_entry == 0)) {
status = MANIFEST_CHILD_NOT_FOUND;
goto error;
}
/* Hash the unneeded TOC data until the entry hash. */
status = flash_hash_update_contents (manifest->flash, entry_addr, hash_addr - entry_addr, hash);
if (status != 0) {
goto error;
}
/* Validate the TOC. */
status = hash->finish (hash, validate_hash, sizeof (validate_hash));
if (status != 0) {
goto error;
}
if (buffer_compare (validate_hash, manifest->state->toc_hash,
manifest->state->toc_hash_length) != 0) {
return MANIFEST_TOC_INVALID;
}
return 0;
error:
hash->cancel (hash);
return status;
}