OvmfPkg/FswHfsPlus/fsw_hfsplus.c
/* Search an HFS+ special file's B-Tree (given by 'bt'), for a search key
 * matching 'sk', using comparison procedure 'k_cmp' to determine when a key
 * match occurs; Once found, skip over 'rec_skip' contiguous records
 * (following the enveloping nodes' 'fLink' pointers if necessary). Finish
 * by filling a caller-provided B-Tree node buffer ('btnode'), and returning
 * a pointer to the trial key of the matching record inside 'btnode', via
 * 'tk_ptr' (NOTE: unlike the search key, the trial key's fields will be
 * returned in unmodified, BigEndian encoding);
 * On error, set fsw_status_t return code acoordingly.
 *
 * NOTE: A HFS+ volume has a few "special" files, linked directly from the
 *       volume header. For the purpose of this driver, we mainly care about
 *       two of them: the "catalog" and "extents" files. All of these files
 *       are organized as B-Tree structures. This means that, overlaid on
 *       top of the linear span of each file there is an array of nodes of
 *       a given size (node_size), internally cross-linked with "pointers"
 *       to parent/child/sibling nodes, which are essentially the "index"
 *       (or 'node-number') of the target node in this overlaid array.
 *       Ultimately, (node-number * node-size) is a byte offset into the
 *       file, to the location where the referenced node's data begins.
 *       Each B-Tree file's "dnode" information is available in the HFS+
 *       volume header. The node at the very beginning of each file (at
 *       index or node-number == 0) contains a "header node", which provides
 *       the 'node-number' of the B-Tree's "root" node, as well as the
 *       'node-size' of all nodes in that B-Tree file.
 */


A HFS+ volume has a few "special" files, linked directly from the
volume header. For the purpose of this driver, we mainly care about
two of them: the "catalog" and "extents" files. All of these files
are organized as B-Tree structures. This means that, overlaid on
top of the linear span of each file there is an array of nodes of
a given size (node_size), internally cross-linked with "pointers"
to parent/child/sibling nodes, which are essentially the "index"
(or 'node-number') of the target node in this overlaid array.
Ultimately, (node-number * node-size) is a byte offset into the
file, to the location where the referenced node's data begins.
Each B-Tree file's "dnode" information is available in the HFS+
volume header.
A HFS + volume has a few " special " files linked directly from the volume header . For the purpose of this driver we mainly care about two of them : the " catalog " and " extents " files . All of these files are organized as B - Tree structures . This means that overlaid on top of the linear span of each file there is an array of nodes of a given size ( node_size ) internally cross - linked with " pointers " to parent / child / sibling nodes which are essentially the " index " ( or ' node - number ' ) of the target node in this overlaid array . Ultimately ( node - number * node - size ) is a byte offset into the file to the location where the referenced node ' s data begins . Each B - Tree file ' s " dnode " information is available in the HFS + volume header .
static fsw_status_t
fsw_hfsplus_bt_search(struct fsw_hfsplus_dnode *bt,
                      HFSPlusBTKey *sk, k_cmp_t k_cmp, fsw_u64 rec_skip,
                      BTNodeDescriptor *btnode, HFSPlusBTKey **tk_ptr)
{
    fsw_u32      node;
    fsw_u16      rec, lo, hi;
    HFSPlusBTKey *tk;    
    int          cmp;
    fsw_status_t status;
    node = bt->bt_root;
    for (;;) {
        status = fsw_hfsplus_read(bt, (fsw_u64)node * bt->bt_ndsz,
                                  bt->bt_ndsz, btnode);
        if (status)
            return status;
        if ((void *)btnode + sizeof(BTNodeDescriptor) !=
            (void *)fsw_hfsplus_bt_get_rec(btnode, bt->bt_ndsz, 0))
            return FSW_VOLUME_CORRUPTED;
        lo = 0;
        hi = fsw_u16_be_swap(btnode->numRecords) - 1;
        while (lo <= hi) {
             rec = (lo + hi) >> 1;
             tk = fsw_hfsplus_bt_get_rec(btnode, bt->bt_ndsz, rec);
             cmp = k_cmp(tk, sk);
             if (cmp < 0)      
                 lo = rec + 1;
             else if (cmp > 0) 
                 hi = rec - 1;
             else {            
                 if (btnode->kind != kBTLeafNode) {
                     hi = rec;
                     break;
                 }
                 if (rec_skip > 0) {
    while (rec_skip >= fsw_u16_be_swap(btnode->numRecords) - rec) {
        fsw_u32 fl = fsw_u32_be_swap(btnode->fLink);
        rec_skip -= fsw_u16_be_swap(btnode->numRecords) - rec;
        rec = 0;
        if (fl == 0)
            return FSW_NOT_FOUND;
        status = fsw_hfsplus_read(bt, (fsw_u64)fl * bt->bt_ndsz,
                                  bt->bt_ndsz, btnode);
        if (status)
            return status;
        if ((void *)btnode + sizeof(BTNodeDescriptor) !=
            (void *)fsw_hfsplus_bt_get_rec(btnode, bt->bt_ndsz, 0))
            return FSW_VOLUME_CORRUPTED;
    }
    rec = rec_skip;
    tk = fsw_hfsplus_bt_get_rec(btnode, bt->bt_ndsz, rec);
                 }
                 *tk_ptr = tk;
                 return FSW_SUCCESS;
             }
        }
        if (btnode->kind != kBTIndexNode)
            break;
        tk = fsw_hfsplus_bt_get_rec(btnode, bt->bt_ndsz, hi);
        node = fsw_hfsplus_bt_idx_get_child(tk);
    }
    return FSW_NOT_FOUND;
}
static fsw_status_t fsw_hfsplus_bt_search ( struct fsw_hfsplus_dnode * bt , HFSPlusBTKey * sk , k_cmp_t k_cmp , fsw_u64 rec_skip , BTNodeDescriptor * btnode , HFSPlusBTKey * * tk_ptr ) { fsw_u32 node ; fsw_u16 rec , lo , hi ; HFSPlusBTKey * tk ; int cmp ; fsw_status_t status ; node = bt -> bt_root ; for ( ; ; ) { status = fsw_hfsplus_read ( bt , ( fsw_u64 ) node * bt -> bt_ndsz , bt -> bt_ndsz , btnode ) ; if ( status ) return status ; if ( ( void * ) btnode + sizeof ( BTNodeDescriptor ) != ( void * ) fsw_hfsplus_bt_get_rec ( btnode , bt -> bt_ndsz , 0 ) ) return FSW_VOLUME_CORRUPTED ; lo = 0 ; hi = fsw_u16_be_swap ( btnode -> numRecords ) - 1 ; while ( lo <= hi ) { rec = ( lo + hi ) >> 1 ; tk = fsw_hfsplus_bt_get_rec ( btnode , bt -> bt_ndsz , rec ) ; cmp = k_cmp ( tk , sk ) ; if ( cmp < 0 ) lo = rec + 1 ; else if ( cmp > 0 ) hi = rec - 1 ; else { if ( btnode -> kind != kBTLeafNode ) { hi = rec ; break ; } if ( rec_skip > 0 ) { while ( rec_skip >= fsw_u16_be_swap ( btnode -> numRecords ) - rec ) { fsw_u32 fl = fsw_u32_be_swap ( btnode -> fLink ) ; rec_skip -= fsw_u16_be_swap ( btnode -> numRecords ) - rec ; rec = 0 ; if ( fl == 0 ) return FSW_NOT_FOUND ; status = fsw_hfsplus_read ( bt , ( fsw_u64 ) fl * bt -> bt_ndsz , bt -> bt_ndsz , btnode ) ; if ( status ) return status ; if ( ( void * ) btnode + sizeof ( BTNodeDescriptor ) != ( void * ) fsw_hfsplus_bt_get_rec ( btnode , bt -> bt_ndsz , 0 ) ) return FSW_VOLUME_CORRUPTED ; } rec = rec_skip ; tk = fsw_hfsplus_bt_get_rec ( btnode , bt -> bt_ndsz , rec ) ; } * tk_ptr = tk ; return FSW_SUCCESS ; } } if ( btnode -> kind != kBTIndexNode ) break ; tk = fsw_hfsplus_bt_get_rec ( btnode , bt -> bt_ndsz , hi ) ; node = fsw_hfsplus_bt_idx_get_child ( tk ) ; } return FSW_NOT_FOUND ; }
Search an HFS+ special file's B-Tree (given by 'bt'), for a search key
 matching 'sk', using comparison procedure 'k_cmp' to determine when a key
 match occurs; Once found, skip over 'rec_skip' contiguous records
 (following the enveloping nodes' 'fLink' pointers if necessary).
Search an HFS + special file ' s B - Tree ( given by ' bt ' ) for a search key matching ' sk ' using comparison procedure ' k_cmp ' to determine when a key match occurs ; Once found skip over ' rec_skip ' contiguous records ( following the enveloping nodes ' ' fLink ' pointers if necessary ) .
// trial key // start searching from the B-Tree root node: // load data for current node into caller-provided buffer 'btnode' // sanity check: record 0 located immediately after node descriptor // search records within current node // access record data, then compare to search key 'sk' // (tk < sk) // (tk > sk) // (tk == sk) // found original 'sk'; fast-forward past 'rec_skip' records // FIXME: clean this up, refactor to make it elegant! // sanity check: record 0 located immediately after node descriptor // success: return pointer to trial key (within btnode) // NOTE: following the binary search, 'hi' now points at the //       record with the largest 'tk' for which (tk <= sk) // on an index node, so descend to child // search key 'sk' not found