123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818 |
- /*
- * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- * You can also choose to distribute this program under the terms of
- * the Unmodified Binary Distribution Licence (as given in the file
- * COPYING.UBDL), provided that you have satisfied its requirements.
- */
-
- FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
- #include <errno.h>
- #include <assert.h>
- #include <ipxe/uaccess.h>
- #include <ipxe/sha256.h>
- #include <ipxe/sha512.h>
- #include <ipxe/hmac.h>
- #include <ipxe/base16.h>
- #include <ipxe/pccrc.h>
-
- /** @file
- *
- * Peer Content Caching and Retrieval: Content Identification [MS-PCCRC]
- *
- */
-
- /******************************************************************************
- *
- * Utility functions
- *
- ******************************************************************************
- */
-
- /**
- * Transcribe hash value (for debugging)
- *
- * @v info Content information
- * @v hash Hash value
- * @ret string Hash value string
- */
- static inline const char *
- peerdist_info_hash_ntoa ( const struct peerdist_info *info, const void *hash ) {
- static char buf[ ( 2 * PEERDIST_DIGEST_MAX_SIZE ) + 1 /* NUL */ ];
- size_t digestsize = info->digestsize;
-
- /* Sanity check */
- assert ( info != NULL );
- assert ( digestsize != 0 );
- assert ( base16_encoded_len ( digestsize ) < sizeof ( buf ) );
-
- /* Transcribe hash value */
- base16_encode ( hash, digestsize, buf, sizeof ( buf ) );
- return buf;
- }
-
- /**
- * Get raw data
- *
- * @v info Content information
- * @v data Data buffer
- * @v offset Starting offset
- * @v len Length
- * @ret rc Return status code
- */
- static int peerdist_info_get ( const struct peerdist_info *info, void *data,
- size_t offset, size_t len ) {
-
- /* Sanity check */
- if ( ( offset > info->raw.len ) ||
- ( len > ( info->raw.len - offset ) ) ) {
- DBGC ( info, "PCCRC %p data underrun at [%zx,%zx) of %zx\n",
- info, offset, ( offset + len ), info->raw.len );
- return -ERANGE;
- }
-
- /* Copy data */
- copy_from_user ( data, info->raw.data, offset, len );
-
- return 0;
- }
-
- /**
- * Populate segment hashes
- *
- * @v segment Content information segment to fill in
- * @v hash Segment hash of data
- * @v secret Segment secret
- */
- static void peerdist_info_segment_hash ( struct peerdist_info_segment *segment,
- const void *hash, const void *secret ){
- const struct peerdist_info *info = segment->info;
- struct digest_algorithm *digest = info->digest;
- uint8_t ctx[digest->ctxsize];
- size_t digestsize = info->digestsize;
- size_t secretsize = digestsize;
- static const uint16_t magic[] = PEERDIST_SEGMENT_ID_MAGIC;
-
- /* Sanity check */
- assert ( digestsize <= sizeof ( segment->hash ) );
- assert ( digestsize <= sizeof ( segment->secret ) );
- assert ( digestsize <= sizeof ( segment->id ) );
-
- /* Get segment hash of data */
- memcpy ( segment->hash, hash, digestsize );
-
- /* Get segment secret */
- memcpy ( segment->secret, secret, digestsize );
-
- /* Calculate segment identifier */
- hmac_init ( digest, ctx, segment->secret, &secretsize );
- assert ( secretsize == digestsize );
- hmac_update ( digest, ctx, segment->hash, digestsize );
- hmac_update ( digest, ctx, magic, sizeof ( magic ) );
- hmac_final ( digest, ctx, segment->secret, &secretsize, segment->id );
- assert ( secretsize == digestsize );
- }
-
- /******************************************************************************
- *
- * Content Information version 1
- *
- ******************************************************************************
- */
-
- /**
- * Get number of blocks within a block description
- *
- * @v info Content information
- * @v offset Block description offset
- * @ret blocks Number of blocks, or negative error
- */
- static int peerdist_info_v1_blocks ( const struct peerdist_info *info,
- size_t offset ) {
- struct peerdist_info_v1_block raw;
- unsigned int blocks;
- int rc;
-
- /* Get block description header */
- if ( ( rc = peerdist_info_get ( info, &raw, offset,
- sizeof ( raw ) ) ) != 0 )
- return rc;
-
- /* Calculate number of blocks */
- blocks = le32_to_cpu ( raw.blocks );
-
- return blocks;
- }
-
- /**
- * Locate block description
- *
- * @v info Content information
- * @v index Segment index
- * @ret offset Block description offset, or negative error
- */
- static ssize_t peerdist_info_v1_block_offset ( const struct peerdist_info *info,
- unsigned int index ) {
- size_t digestsize = info->digestsize;
- unsigned int i;
- size_t offset;
- int blocks;
- int rc;
-
- /* Sanity check */
- assert ( index < info->segments );
-
- /* Calculate offset of first block description */
- offset = ( sizeof ( struct peerdist_info_v1 ) +
- ( info->segments *
- sizeof ( peerdist_info_v1_segment_t ( digestsize ) ) ) );
-
- /* Iterate over block descriptions until we find this segment */
- for ( i = 0 ; i < index ; i++ ) {
-
- /* Get number of blocks */
- blocks = peerdist_info_v1_blocks ( info, offset );
- if ( blocks < 0 ) {
- rc = blocks;
- DBGC ( info, "PCCRC %p segment %d could not get number "
- "of blocks: %s\n", info, i, strerror ( rc ) );
- return rc;
- }
-
- /* Move to next block description */
- offset += sizeof ( peerdist_info_v1_block_t ( digestsize,
- blocks ) );
- }
-
- return offset;
- }
-
- /**
- * Populate content information
- *
- * @v info Content information to fill in
- * @ret rc Return status code
- */
- static int peerdist_info_v1 ( struct peerdist_info *info ) {
- struct peerdist_info_v1 raw;
- struct peerdist_info_segment first;
- struct peerdist_info_segment last;
- size_t first_skip;
- size_t last_skip;
- size_t last_read;
- int rc;
-
- /* Get raw header */
- if ( ( rc = peerdist_info_get ( info, &raw, 0, sizeof ( raw ) ) ) != 0){
- DBGC ( info, "PCCRC %p could not get V1 content information: "
- "%s\n", info, strerror ( rc ) );
- return rc;
- }
- assert ( raw.version.raw == cpu_to_le16 ( PEERDIST_INFO_V1 ) );
-
- /* Determine hash algorithm */
- switch ( raw.hash ) {
- case cpu_to_le32 ( PEERDIST_INFO_V1_HASH_SHA256 ) :
- info->digest = &sha256_algorithm;
- break;
- case cpu_to_le32 ( PEERDIST_INFO_V1_HASH_SHA384 ) :
- info->digest = &sha384_algorithm;
- break;
- case cpu_to_le32 ( PEERDIST_INFO_V1_HASH_SHA512 ) :
- info->digest = &sha512_algorithm;
- break;
- default:
- DBGC ( info, "PCCRC %p unsupported hash algorithm %#08x\n",
- info, le32_to_cpu ( raw.hash ) );
- return -ENOTSUP;
- }
- info->digestsize = info->digest->digestsize;
- assert ( info->digest != NULL );
- DBGC2 ( info, "PCCRC %p using %s[%zd]\n",
- info, info->digest->name, ( info->digestsize * 8 ) );
-
- /* Calculate number of segments */
- info->segments = le32_to_cpu ( raw.segments );
-
- /* Get first segment */
- if ( ( rc = peerdist_info_segment ( info, &first, 0 ) ) != 0 )
- return rc;
-
- /* Calculate range start offset */
- info->range.start = first.range.start;
-
- /* Calculate trimmed range start offset */
- first_skip = le32_to_cpu ( raw.first );
- info->trim.start = ( first.range.start + first_skip );
-
- /* Get last segment */
- if ( ( rc = peerdist_info_segment ( info, &last,
- ( info->segments - 1 ) ) ) != 0 )
- return rc;
-
- /* Calculate range end offset */
- info->range.end = last.range.end;
-
- /* Calculate trimmed range end offset */
- if ( raw.last ) {
- /* Explicit length to include from last segment is given */
- last_read = le32_to_cpu ( raw.last );
- last_skip = ( last.index ? 0 : first_skip );
- info->trim.end = ( last.range.start + last_skip + last_read );
- } else {
- /* No explicit length given: range extends to end of segment */
- info->trim.end = last.range.end;
- }
-
- return 0;
- }
-
- /**
- * Populate content information segment
- *
- * @v segment Content information segment to fill in
- * @ret rc Return status code
- */
- static int peerdist_info_v1_segment ( struct peerdist_info_segment *segment ) {
- const struct peerdist_info *info = segment->info;
- size_t digestsize = info->digestsize;
- peerdist_info_v1_segment_t ( digestsize ) raw;
- ssize_t raw_offset;
- int blocks;
- int rc;
-
- /* Sanity checks */
- assert ( segment->index < info->segments );
-
- /* Get raw description */
- raw_offset = ( sizeof ( struct peerdist_info_v1 ) +
- ( segment->index * sizeof ( raw ) ) );
- if ( ( rc = peerdist_info_get ( info, &raw, raw_offset,
- sizeof ( raw ) ) ) != 0 ) {
- DBGC ( info, "PCCRC %p segment %d could not get segment "
- "description: %s\n", info, segment->index,
- strerror ( rc ) );
- return rc;
- }
-
- /* Calculate start offset of this segment */
- segment->range.start = le64_to_cpu ( raw.segment.offset );
-
- /* Calculate end offset of this segment */
- segment->range.end = ( segment->range.start +
- le32_to_cpu ( raw.segment.len ) );
-
- /* Calculate block size of this segment */
- segment->blksize = le32_to_cpu ( raw.segment.blksize );
-
- /* Locate block description for this segment */
- raw_offset = peerdist_info_v1_block_offset ( info, segment->index );
- if ( raw_offset < 0 ) {
- rc = raw_offset;
- return rc;
- }
-
- /* Get number of blocks */
- blocks = peerdist_info_v1_blocks ( info, raw_offset );
- if ( blocks < 0 ) {
- rc = blocks;
- DBGC ( info, "PCCRC %p segment %d could not get number of "
- "blocks: %s\n", info, segment->index, strerror ( rc ) );
- return rc;
- }
- segment->blocks = blocks;
-
- /* Calculate segment hashes */
- peerdist_info_segment_hash ( segment, raw.hash, raw.secret );
-
- return 0;
- }
-
- /**
- * Populate content information block
- *
- * @v block Content information block to fill in
- * @ret rc Return status code
- */
- static int peerdist_info_v1_block ( struct peerdist_info_block *block ) {
- const struct peerdist_info_segment *segment = block->segment;
- const struct peerdist_info *info = segment->info;
- size_t digestsize = info->digestsize;
- peerdist_info_v1_block_t ( digestsize, segment->blocks ) raw;
- ssize_t raw_offset;
- int rc;
-
- /* Sanity checks */
- assert ( block->index < segment->blocks );
-
- /* Calculate start offset of this block */
- block->range.start = ( segment->range.start +
- ( block->index * segment->blksize ) );
-
- /* Calculate end offset of this block */
- block->range.end = ( block->range.start + segment->blksize );
- if ( block->range.end > segment->range.end )
- block->range.end = segment->range.end;
-
- /* Locate block description */
- raw_offset = peerdist_info_v1_block_offset ( info, segment->index );
- if ( raw_offset < 0 ) {
- rc = raw_offset;
- return rc;
- }
-
- /* Get block hash */
- raw_offset += offsetof ( typeof ( raw ), hash[block->index] );
- if ( ( rc = peerdist_info_get ( info, block->hash, raw_offset,
- digestsize ) ) != 0 ) {
- DBGC ( info, "PCCRC %p segment %d block %d could not get "
- "hash: %s\n", info, segment->index, block->index,
- strerror ( rc ) );
- return rc;
- }
-
- return 0;
- }
-
- /** Content information version 1 operations */
- static struct peerdist_info_operations peerdist_info_v1_operations = {
- .info = peerdist_info_v1,
- .segment = peerdist_info_v1_segment,
- .block = peerdist_info_v1_block,
- };
-
- /******************************************************************************
- *
- * Content Information version 2
- *
- ******************************************************************************
- */
-
- /** A segment cursor */
- struct peerdist_info_v2_cursor {
- /** Raw data offset */
- size_t offset;
- /** Number of segments remaining within this chunk */
- unsigned int remaining;
- /** Accumulated segment length */
- size_t len;
- };
-
- /**
- * Initialise segment cursor
- *
- * @v cursor Segment cursor
- */
- static inline void
- peerdist_info_v2_cursor_init ( struct peerdist_info_v2_cursor *cursor ) {
-
- /* Initialise cursor */
- cursor->offset = ( sizeof ( struct peerdist_info_v2 ) +
- sizeof ( struct peerdist_info_v2_chunk ) );
- cursor->remaining = 0;
- cursor->len = 0;
- }
-
- /**
- * Update segment cursor to next segment description
- *
- * @v info Content information
- * @v offset Current offset
- * @v remaining Number of segments remaining within this chunk
- * @ret rc Return status code
- */
- static int
- peerdist_info_v2_cursor_next ( const struct peerdist_info *info,
- struct peerdist_info_v2_cursor *cursor ) {
- size_t digestsize = info->digestsize;
- peerdist_info_v2_segment_t ( digestsize ) raw;
- struct peerdist_info_v2_chunk chunk;
- int rc;
-
- /* Get chunk description if applicable */
- if ( ! cursor->remaining ) {
-
- /* Get chunk description */
- if ( ( rc = peerdist_info_get ( info, &chunk,
- ( cursor->offset -
- sizeof ( chunk ) ),
- sizeof ( chunk ) ) ) != 0 )
- return rc;
-
- /* Update number of segments remaining */
- cursor->remaining = ( be32_to_cpu ( chunk.len ) /
- sizeof ( raw ) );
- }
-
- /* Get segment description header */
- if ( ( rc = peerdist_info_get ( info, &raw.segment, cursor->offset,
- sizeof ( raw.segment ) ) ) != 0 )
- return rc;
-
- /* Update cursor */
- cursor->offset += sizeof ( raw );
- cursor->remaining--;
- if ( ! cursor->remaining )
- cursor->offset += sizeof ( chunk );
- cursor->len += be32_to_cpu ( raw.segment.len );
-
- return 0;
- }
-
- /**
- * Get number of segments and total length
- *
- * @v info Content information
- * @v len Length to fill in
- * @ret rc Number of segments, or negative error
- */
- static int peerdist_info_v2_segments ( const struct peerdist_info *info,
- size_t *len ) {
- struct peerdist_info_v2_cursor cursor;
- unsigned int segments;
- int rc;
-
- /* Iterate over all segments */
- for ( peerdist_info_v2_cursor_init ( &cursor ), segments = 0 ;
- cursor.offset < info->raw.len ; segments++ ) {
-
- /* Update segment cursor */
- if ( ( rc = peerdist_info_v2_cursor_next ( info,
- &cursor ) ) != 0 ) {
- DBGC ( info, "PCCRC %p segment %d could not update "
- "segment cursor: %s\n",
- info, segments, strerror ( rc ) );
- return rc;
- }
- }
-
- /* Record accumulated length */
- *len = cursor.len;
-
- return segments;
- }
-
- /**
- * Populate content information
- *
- * @v info Content information to fill in
- * @ret rc Return status code
- */
- static int peerdist_info_v2 ( struct peerdist_info *info ) {
- struct peerdist_info_v2 raw;
- size_t len = 0;
- int segments;
- int rc;
-
- /* Get raw header */
- if ( ( rc = peerdist_info_get ( info, &raw, 0, sizeof ( raw ) ) ) != 0){
- DBGC ( info, "PCCRC %p could not get V2 content information: "
- "%s\n", info, strerror ( rc ) );
- return rc;
- }
- assert ( raw.version.raw == cpu_to_le16 ( PEERDIST_INFO_V2 ) );
-
- /* Determine hash algorithm */
- switch ( raw.hash ) {
- case PEERDIST_INFO_V2_HASH_SHA512_TRUNC :
- info->digest = &sha512_algorithm;
- info->digestsize = ( 256 / 8 );
- break;
- default:
- DBGC ( info, "PCCRC %p unsupported hash algorithm %#02x\n",
- info, raw.hash );
- return -ENOTSUP;
- }
- assert ( info->digest != NULL );
- DBGC2 ( info, "PCCRC %p using %s[%zd]\n",
- info, info->digest->name, ( info->digestsize * 8 ) );
-
- /* Calculate number of segments and total length */
- segments = peerdist_info_v2_segments ( info, &len );
- if ( segments < 0 ) {
- rc = segments;
- DBGC ( info, "PCCRC %p could not get segment count and length: "
- "%s\n", info, strerror ( rc ) );
- return rc;
- }
- info->segments = segments;
-
- /* Calculate range start offset */
- info->range.start = be64_to_cpu ( raw.offset );
-
- /* Calculate trimmed range start offset */
- info->trim.start = ( info->range.start + be32_to_cpu ( raw.first ) );
-
- /* Calculate range end offset */
- info->range.end = ( info->range.start + len );
-
- /* Calculate trimmed range end offset */
- info->trim.end = ( raw.len ? be64_to_cpu ( raw.len ) :
- info->range.end );
-
- return 0;
- }
-
- /**
- * Populate content information segment
- *
- * @v segment Content information segment to fill in
- * @ret rc Return status code
- */
- static int peerdist_info_v2_segment ( struct peerdist_info_segment *segment ) {
- const struct peerdist_info *info = segment->info;
- size_t digestsize = info->digestsize;
- peerdist_info_v2_segment_t ( digestsize ) raw;
- struct peerdist_info_v2_cursor cursor;
- unsigned int index;
- size_t len;
- int rc;
-
- /* Sanity checks */
- assert ( segment->index < info->segments );
-
- /* Iterate over all segments before the target segment */
- for ( peerdist_info_v2_cursor_init ( &cursor ), index = 0 ;
- index < segment->index ; index++ ) {
-
- /* Update segment cursor */
- if ( ( rc = peerdist_info_v2_cursor_next ( info,
- &cursor ) ) != 0 ) {
- DBGC ( info, "PCCRC %p segment %d could not update "
- "segment cursor: %s\n",
- info, index, strerror ( rc ) );
- return rc;
- }
- }
-
- /* Get raw description */
- if ( ( rc = peerdist_info_get ( info, &raw, cursor.offset,
- sizeof ( raw ) ) ) != 0 ) {
- DBGC ( info, "PCCRC %p segment %d could not get segment "
- "description: %s\n",
- info, segment->index, strerror ( rc ) );
- return rc;
- }
-
- /* Calculate start offset of this segment */
- segment->range.start = ( info->range.start + cursor.len );
-
- /* Calculate end offset of this segment */
- len = be32_to_cpu ( raw.segment.len );
- segment->range.end = ( segment->range.start + len );
-
- /* Model as a segment containing a single block */
- segment->blocks = 1;
- segment->blksize = len;
-
- /* Calculate segment hashes */
- peerdist_info_segment_hash ( segment, raw.hash, raw.secret );
-
- return 0;
- }
-
- /**
- * Populate content information block
- *
- * @v block Content information block to fill in
- * @ret rc Return status code
- */
- static int peerdist_info_v2_block ( struct peerdist_info_block *block ) {
- const struct peerdist_info_segment *segment = block->segment;
- const struct peerdist_info *info = segment->info;
- size_t digestsize = info->digestsize;
-
- /* Sanity checks */
- assert ( block->index < segment->blocks );
-
- /* Model as a block covering the whole segment */
- memcpy ( &block->range, &segment->range, sizeof ( block->range ) );
- memcpy ( block->hash, segment->hash, digestsize );
-
- return 0;
- }
-
- /** Content information version 2 operations */
- static struct peerdist_info_operations peerdist_info_v2_operations = {
- .block = peerdist_info_v2_block,
- .segment = peerdist_info_v2_segment,
- .info = peerdist_info_v2,
- };
-
- /******************************************************************************
- *
- * Content Information
- *
- ******************************************************************************
- */
-
- /**
- * Populate content information
- *
- * @v data Raw data
- * @v len Length of raw data
- * @v info Content information to fill in
- * @ret rc Return status code
- */
- int peerdist_info ( userptr_t data, size_t len, struct peerdist_info *info ) {
- union peerdist_info_version version;
- int rc;
-
- /* Initialise structure */
- memset ( info, 0, sizeof ( *info ) );
- info->raw.data = data;
- info->raw.len = len;
-
- /* Get version */
- if ( ( rc = peerdist_info_get ( info, &version, 0,
- sizeof ( version ) ) ) != 0 ) {
- DBGC ( info, "PCCRC %p could not get version: %s\n",
- info, strerror ( rc ) );
- return rc;
- }
- DBGC2 ( info, "PCCRC %p version %d.%d\n",
- info, version.major, version.minor );
-
- /* Determine version */
- switch ( version.raw ) {
- case cpu_to_le16 ( PEERDIST_INFO_V1 ) :
- info->op = &peerdist_info_v1_operations;
- break;
- case cpu_to_le16 ( PEERDIST_INFO_V2 ) :
- info->op = &peerdist_info_v2_operations;
- break;
- default:
- DBGC ( info, "PCCRC %p unsupported version %d.%d\n",
- info, version.major, version.minor );
- return -ENOTSUP;
- }
- assert ( info->op != NULL );
- assert ( info->op->info != NULL );
-
- /* Populate content information */
- if ( ( rc = info->op->info ( info ) ) != 0 )
- return rc;
-
- DBGC2 ( info, "PCCRC %p range [%08zx,%08zx) covers [%08zx,%08zx) with "
- "%d segments\n", info, info->range.start, info->range.end,
- info->trim.start, info->trim.end, info->segments );
- return 0;
- }
-
- /**
- * Populate content information segment
- *
- * @v info Content information
- * @v segment Content information segment to fill in
- * @v index Segment index
- * @ret rc Return status code
- */
- int peerdist_info_segment ( const struct peerdist_info *info,
- struct peerdist_info_segment *segment,
- unsigned int index ) {
- int rc;
-
- /* Sanity checks */
- assert ( info != NULL );
- assert ( info->op != NULL );
- assert ( info->op->segment != NULL );
- if ( index >= info->segments ) {
- DBGC ( info, "PCCRC %p segment %d of [0,%d) out of range\n",
- info, index, info->segments );
- return -ERANGE;
- }
-
- /* Initialise structure */
- memset ( segment, 0, sizeof ( *segment ) );
- segment->info = info;
- segment->index = index;
-
- /* Populate content information segment */
- if ( ( rc = info->op->segment ( segment ) ) != 0 )
- return rc;
-
- DBGC2 ( info, "PCCRC %p segment %d range [%08zx,%08zx) with %d "
- "blocks\n", info, segment->index, segment->range.start,
- segment->range.end, segment->blocks );
- DBGC2 ( info, "PCCRC %p segment %d digest %s\n", info, segment->index,
- peerdist_info_hash_ntoa ( info, segment->hash ) );
- DBGC2 ( info, "PCCRC %p segment %d secret %s\n", info, segment->index,
- peerdist_info_hash_ntoa ( info, segment->secret ) );
- DBGC2 ( info, "PCCRC %p segment %d identf %s\n", info, segment->index,
- peerdist_info_hash_ntoa ( info, segment->id ) );
- return 0;
- }
-
- /**
- * Populate content information block
- *
- * @v segment Content information segment
- * @v block Content information block to fill in
- * @v index Block index
- * @ret rc Return status code
- */
- int peerdist_info_block ( const struct peerdist_info_segment *segment,
- struct peerdist_info_block *block,
- unsigned int index ) {
- const struct peerdist_info *info = segment->info;
- size_t start;
- size_t end;
- int rc;
-
- /* Sanity checks */
- assert ( segment != NULL );
- assert ( info != NULL );
- assert ( info->op != NULL );
- assert ( info->op->block != NULL );
- if ( index >= segment->blocks ) {
- DBGC ( info, "PCCRC %p segment %d block %d of [0,%d) out of "
- "range\n", info, segment->index, index, segment->blocks);
- return -ERANGE;
- }
-
- /* Initialise structure */
- memset ( block, 0, sizeof ( *block ) );
- block->segment = segment;
- block->index = index;
-
- /* Populate content information block */
- if ( ( rc = info->op->block ( block ) ) != 0 )
- return rc;
-
- /* Calculate trimmed range */
- start = block->range.start;
- if ( start < info->trim.start )
- start = info->trim.start;
- end = block->range.end;
- if ( end > info->trim.end )
- end = info->trim.end;
- if ( end < start )
- end = start;
- block->trim.start = start;
- block->trim.end = end;
-
- DBGC2 ( info, "PCCRC %p segment %d block %d hash %s\n",
- info, segment->index, block->index,
- peerdist_info_hash_ntoa ( info, block->hash ) );
- DBGC2 ( info, "PCCRC %p segment %d block %d range [%08zx,%08zx) covers "
- "[%08zx,%08zx)\n", info, segment->index, block->index,
- block->range.start, block->range.end, block->trim.start,
- block->trim.end );
- return 0;
- }
|