int manifest_flash_get_child_elements_info()

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;
}