/**
 * Constructs a full data block representation from the specified minimal
 * block entry.  However, the resultant block's pointers are set to null,
 * rather than populated via hash table lookups.  This behavior is useful when
 * the RAM representation has not been fully constructed yet.
 *
 * @param out_block             On success, this gets populated with the data
 *                                  block information.
 * @param block_entry           The source block entry to convert.
 *
 * @return                      0 on success; nonzero on failure.
 */
int
nffs_block_from_hash_entry_no_ptrs(struct nffs_block *out_block,
                                   struct nffs_hash_entry *block_entry)
{
    struct nffs_disk_block disk_block;
    uint32_t area_offset;
    uint8_t area_idx;
    int rc;

    assert(nffs_hash_id_is_block(block_entry->nhe_id));

    if (nffs_hash_entry_is_dummy(block_entry)) {
        /*
         * We can't read this from disk so we'll be missing filling in anything
         * not already in inode_entry (e.g., prev_id).
         */
        out_block->nb_hash_entry = block_entry;
        return FS_ENOENT; /* let caller know it's a partial inode_entry */
    }

    nffs_flash_loc_expand(block_entry->nhe_flash_loc, &area_idx, &area_offset);
    rc = nffs_block_read_disk(area_idx, area_offset, &disk_block);
    if (rc != 0) {
        return rc;
    }

    out_block->nb_hash_entry = block_entry;
    nffs_block_from_disk_no_ptrs(out_block, &disk_block);

    return 0;
}
static int
nffs_block_from_disk(struct nffs_block *out_block,
                     const struct nffs_disk_block *disk_block,
                     uint8_t area_idx, uint32_t area_offset)
{
    nffs_block_from_disk_no_ptrs(out_block, disk_block);

    out_block->nb_inode_entry = nffs_hash_find_inode(disk_block->ndb_inode_id);
    if (out_block->nb_inode_entry == NULL) {
        return FS_ECORRUPT;
    }

    if (disk_block->ndb_prev_id != NFFS_ID_NONE) {
        out_block->nb_prev = nffs_hash_find_block(disk_block->ndb_prev_id);
        if (out_block->nb_prev == NULL) {
            return FS_ECORRUPT;
        }
    }

    return 0;
}
/**
 * Constructs a full data block representation from the specified minimal
 * block entry.  However, the resultant block's pointers are set to null,
 * rather than populated via hash table lookups.  This behavior is useful when
 * the RAM representation has not been fully constructed yet.
 *
 * @param out_block             On success, this gets populated with the data
 *                                  block information.
 * @param block_entry           The source block entry to convert.
 *
 * @return                      0 on success; nonzero on failure.
 */
int
nffs_block_from_hash_entry_no_ptrs(struct nffs_block *out_block,
                                   struct nffs_hash_entry *block_entry)
{
    struct nffs_disk_block disk_block;
    uint32_t area_offset;
    uint8_t area_idx;
    int rc;

    assert(nffs_hash_id_is_block(block_entry->nhe_id));

    nffs_flash_loc_expand(block_entry->nhe_flash_loc, &area_idx, &area_offset);
    rc = nffs_block_read_disk(area_idx, area_offset, &disk_block);
    if (rc != 0) {
        return rc;
    }

    out_block->nb_hash_entry = block_entry;
    nffs_block_from_disk_no_ptrs(out_block, &disk_block);

    return 0;
}
/**
 * Constructs a block representation from a disk record.  If the disk block
 * references other objects (inode or previous data block), the resulting block
 * object is populated with pointers to the referenced objects.  If the any
 * referenced objects are not present in the NFFS RAM representation, this
 * indicates file system corruption.  In this case, the resulting block is
 * populated with all valid references, and an FS_ECORRUPT code is returned.
 *
 * @param out_block             The resulting block is written here (regardless
 *                                  of this function's return code).
 * @param disk_block            The source disk record to convert.
 *
 * @return                      0 if the block was successfully constructed;
 *                              FS_ECORRUPT if one or more pointers could not
 *                                  be filled in due to file system corruption.
 */
static int
nffs_block_from_disk(struct nffs_block *out_block,
                     const struct nffs_disk_block *disk_block)
{
    int rc;

    rc = 0;

    nffs_block_from_disk_no_ptrs(out_block, disk_block);

    out_block->nb_inode_entry = nffs_hash_find_inode(disk_block->ndb_inode_id);
    if (out_block->nb_inode_entry == NULL) {
        rc = FS_ECORRUPT;
    }

    if (disk_block->ndb_prev_id != NFFS_ID_NONE) {
        out_block->nb_prev = nffs_hash_find_block(disk_block->ndb_prev_id);
        if (out_block->nb_prev == NULL) {
            rc = FS_ECORRUPT;
        }
    }

    return rc;
}