Skip to content

Commit

Permalink
hdata: Add an idata array iterator
Browse files Browse the repository at this point in the history
Adds HDIF_get_iarray() which retrieves and validates an internal array
header and HDIF_iarray_for_each() for walking the individual array
entries. This reduces the amount of get-then-check boilerplate that
we have with the existing HDIF_get_iarray_item() method for iterating
internal data arrays.

Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
  • Loading branch information
oohal authored and stewartsmith committed Sep 15, 2017
1 parent c77b974 commit 0abc3af
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 0 deletions.
69 changes: 69 additions & 0 deletions hdata/hdif.c
Expand Up @@ -96,6 +96,75 @@ int HDIF_get_iarray_size(const struct HDIF_common_hdr *hdif, unsigned int di)
return be32_to_cpu(ahdr->ecnt);
}

/*
* Returns NULL and sets *items to zero when:
*
* a) Array extends beyond bounds (hard error)
* b) The array is empty (soft error)
* c) The item size is zero (soft error)
* d) The array is missing (soft error)
*
* b, c) are bugs in the input data so they generate backtraces.
*
* If you care about the soft error cases, retrive the array header manually
* with HDIF_get_idata().
*/
const struct HDIF_array_hdr *HDIF_get_iarray(const struct HDIF_common_hdr *hdif,
unsigned int di, unsigned int *items)
{
const struct HDIF_array_hdr *arr;
unsigned int req_size, size, elements;
unsigned int actual_sz, alloc_sz, offset;

arr = HDIF_get_idata(hdif, di, &size);

if(items)
*items = 0;

if (!arr || !size)
return NULL;

/* base size of an Idata array header */
offset = be32_to_cpu(arr->offset);
actual_sz = be32_to_cpu(arr->eactsz);
alloc_sz = be32_to_cpu(arr->esize);
elements = be32_to_cpu(arr->ecnt);

/* actual size should always be smaller than allocated */
if (alloc_sz < actual_sz) {
prerror("HDIF %.6s iarray %u has actsz (%u) < alloc_sz (%u)\n)",
hdif->id, di, actual_sz, alloc_sz);
backtrace();
return NULL;
}

req_size = elements * alloc_sz + offset;
if (req_size > size) {
prerror("HDIF: %.6s iarray %u requires %#x bytes, but only %#x are allocated!\n",
hdif->id, di, req_size, size);
backtrace();
return NULL;
}

if (!elements || !actual_sz)
return NULL;

if (items)
*items = elements;

return arr;
}

const void *HDIF_iarray_item(const struct HDIF_array_hdr *ahdr,
unsigned int index)
{
if (!ahdr || index >= be32_to_cpu(ahdr->ecnt))
return NULL;

return (const void * )ahdr + be32_to_cpu(ahdr->offset) +
index * be32_to_cpu(ahdr->esize);
}

struct HDIF_child_ptr *
HDIF_child_arr(const struct HDIF_common_hdr *hdif, unsigned int idx)
{
Expand Down
18 changes: 18 additions & 0 deletions hdata/hdif.h
Expand Up @@ -105,6 +105,24 @@ extern const void *HDIF_get_iarray_item(const struct HDIF_common_hdr *hdif,
unsigned int di,
unsigned int ai, unsigned int *size);

/* HDIF_get_iarray - Get a pointer to an internal array header
*
* @hdif : HDIF structure pointer
* @di : Index of the idata pointer
* @ai : Index in the resulting array
* @size : Return the entry actual size (or NULL if ignored)
*/
extern const struct HDIF_array_hdr *HDIF_get_iarray(
const struct HDIF_common_hdr *hdif, unsigned int di,
unsigned int *items);

extern const void *HDIF_iarray_item(const struct HDIF_array_hdr *hdif,
unsigned int index);

#define HDIF_iarray_for_each(arr, idx, ptr) \
for (idx = 0, ptr = HDIF_iarray_item(arr, idx); \
ptr; idx++, ptr = HDIF_iarray_item(arr, idx))

/* HDIF_get_iarray_size - Get the number of elements of an internal data array
*
* @hdif : HDIF structure pointer
Expand Down

0 comments on commit 0abc3af

Please sign in to comment.