gptsync/gptsync.c
static VOID generate_hybrid_mbr(VOID) {
    UINTN i, k, iter, count_active;
    UINT64 first_used_lba;

    new_mbr_part_count = 1;
    first_used_lba = (UINT64) MAX_MBR_LBA + (UINT64) 1;

    // Copy partitions in three passes....
    // First, do FAT and NTFS partitions....
    i = 0;
    do {
        if ((gpt_parts[i].start_lba > 0) && (gpt_parts[i].end_lba > 0) &&
            (gpt_parts[i].end_lba <= MAX_MBR_LBA) &&                    /* Within MBR limits */
            (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) && /* MS Basic Data GPT type code */
            (gpt_parts[i].mbr_type != 0x83)) {                          /* Not containing Linux filesystem */
           copy_gpt_to_new_mbr(i, new_mbr_part_count);
           if (new_mbr_parts[new_mbr_part_count].start_lba < first_used_lba)
              first_used_lba = new_mbr_parts[new_mbr_part_count].start_lba;

           new_mbr_part_count++;
        }
        i++;
    } while (i < gpt_part_count && new_mbr_part_count <= 3);

    // Second, do Linux partitions. Note that we start from the END of the
    // partition list, so as to maximize the space covered by the 0xEE
    // partition if there are several Linux partitions before other hybridized
    // partitions.
    i = gpt_part_count - 1; // Note that gpt_part_count can't be 0; filtered by check_gpt()
    while (i < gpt_part_count && new_mbr_part_count <= 3) { // if too few GPT partitions, i loops around to a huge value
        if ((gpt_parts[i].start_lba > 0) && (gpt_parts[i].end_lba > 0) &&
            (gpt_parts[i].end_lba <= MAX_MBR_LBA) &&
            ((gpt_parts[i].gpt_parttype->kind == GPT_KIND_DATA) || (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA)) &&
            (gpt_parts[i].mbr_type == 0x83)) {
           copy_gpt_to_new_mbr(i, new_mbr_part_count);
           if (new_mbr_parts[new_mbr_part_count].start_lba < first_used_lba)
              first_used_lba = new_mbr_parts[new_mbr_part_count].start_lba;

           new_mbr_part_count++;
       }
       i--;
    } // while

    // Third, do anything that's left to cover uncovered spaces; but this requires
    // first creating the EFI protective entry, since we don't want to bother with
    // anything already covered by this entry....
    new_mbr_parts[0].index     = 0;
    new_mbr_parts[0].start_lba = 1;
    new_mbr_parts[0].end_lba   = (disk_size() > first_used_lba) ? (first_used_lba - 1) : disk_size() - 1;
    if (new_mbr_parts[0].end_lba > MAX_MBR_LBA)
       new_mbr_parts[0].end_lba = MAX_MBR_LBA;
    new_mbr_parts[0].mbr_type  = 0xEE;
    i = 0;
    while (i < gpt_part_count && new_mbr_part_count <= 3) {
       if ((gpt_parts[i].start_lba > new_mbr_parts[0].end_lba) && (gpt_parts[i].end_lba > 0) &&
           (gpt_parts[i].end_lba <= MAX_MBR_LBA) &&
           (gpt_parts[i].gpt_parttype->kind != GPT_KIND_BASIC_DATA) &&
           (gpt_parts[i].mbr_type != 0x83)) {
          copy_gpt_to_new_mbr(i, new_mbr_part_count);
          new_mbr_part_count++;
       }
       i++;
    } // while

    // find matching partitions in the old MBR table, copy undetected details....
    for (i = 1; i < new_mbr_part_count; i++) {
       for (k = 0; k < mbr_part_count; k++) {
           if (mbr_parts[k].start_lba == new_mbr_parts[i].start_lba) {
               // keep type if not detected
               if (new_mbr_parts[i].mbr_type == 0)
                   new_mbr_parts[i].mbr_type = mbr_parts[k].mbr_type;
               // keep active flag
               new_mbr_parts[i].active = mbr_parts[k].active;
               break;
           } // if
       } // for (k...)
       if (new_mbr_parts[i].mbr_type == 0) {
          // final fallback: set to a (hopefully) unused type
          new_mbr_parts[i].mbr_type = 0xc0;
       } // if
    } // for (i...)

    sort_mbr(new_mbr_parts);

    // make sure there's exactly one active partition
    for (iter = 0; iter < 3; iter++) {
        // check
        count_active = 0;
        for (i = 0; i < new_mbr_part_count; i++)
            if (new_mbr_parts[i].active)
                count_active++;
        if (count_active == 1)
            break;

        // set active on the first matching partition
        if (count_active == 0) {
            for (i = 0; i < new_mbr_part_count; i++) {
                if (((new_mbr_parts[i].mbr_type == 0x07 ||    // NTFS
                      new_mbr_parts[i].mbr_type == 0x0b ||    // FAT32
                      new_mbr_parts[i].mbr_type == 0x0c)) ||  // FAT32 (LBA)
                    (iter >= 1 && (new_mbr_parts[i].mbr_type == 0x83)) ||  // Linux
                    (iter >= 2 && i > 0)) {
                    new_mbr_parts[i].active = TRUE;
                    break;
                }
            }
        } else if (count_active > 1 && iter == 0) {
            // too many active partitions, try deactivating the ESP / EFI Protective entry
            if ((new_mbr_parts[0].mbr_type == 0xee || new_mbr_parts[0].mbr_type == 0xef) &&
                new_mbr_parts[0].active) {
                new_mbr_parts[0].active = FALSE;
            }
        } else if (count_active > 1 && iter > 0) {
            // too many active partitions, deactivate all but the first one
            count_active = 0;
            for (i = 0; i < new_mbr_part_count; i++)
                if (new_mbr_parts[i].active) {
                    if (count_active > 0)
                        new_mbr_parts[i].active = FALSE;
                    count_active++;
                }
        }
    } // for
}
// Generate a hybrid MBR based on the current GPT. Stores the result in the
// new_mbr_parts[] array.
Generate a hybrid MBR based on the current GPT. Stores the result in the
new_mbr_parts[] array.
Generate a hybrid MBR based on the current GPT . Stores the result in the new_mbr_parts [] array .
static VOID generate_hybrid_mbr(VOID) {
    UINTN i, k, iter, count_active;
    UINT64 first_used_lba;
    new_mbr_part_count = 1;
    first_used_lba = (UINT64) MAX_MBR_LBA + (UINT64) 1;
    i = 0;
    do {
        if ((gpt_parts[i].start_lba > 0) && (gpt_parts[i].end_lba > 0) &&
            (gpt_parts[i].end_lba <= MAX_MBR_LBA) &&                    
            (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA) && 
            (gpt_parts[i].mbr_type != 0x83)) {                          
           copy_gpt_to_new_mbr(i, new_mbr_part_count);
           if (new_mbr_parts[new_mbr_part_count].start_lba < first_used_lba)
              first_used_lba = new_mbr_parts[new_mbr_part_count].start_lba;
           new_mbr_part_count++;
        }
        i++;
    } while (i < gpt_part_count && new_mbr_part_count <= 3);
    i = gpt_part_count - 1; 
    while (i < gpt_part_count && new_mbr_part_count <= 3) { 
        if ((gpt_parts[i].start_lba > 0) && (gpt_parts[i].end_lba > 0) &&
            (gpt_parts[i].end_lba <= MAX_MBR_LBA) &&
            ((gpt_parts[i].gpt_parttype->kind == GPT_KIND_DATA) || (gpt_parts[i].gpt_parttype->kind == GPT_KIND_BASIC_DATA)) &&
            (gpt_parts[i].mbr_type == 0x83)) {
           copy_gpt_to_new_mbr(i, new_mbr_part_count);
           if (new_mbr_parts[new_mbr_part_count].start_lba < first_used_lba)
              first_used_lba = new_mbr_parts[new_mbr_part_count].start_lba;
           new_mbr_part_count++;
       }
       i--;
    } 
    new_mbr_parts[0].index     = 0;
    new_mbr_parts[0].start_lba = 1;
    new_mbr_parts[0].end_lba   = (disk_size() > first_used_lba) ? (first_used_lba - 1) : disk_size() - 1;
    if (new_mbr_parts[0].end_lba > MAX_MBR_LBA)
       new_mbr_parts[0].end_lba = MAX_MBR_LBA;
    new_mbr_parts[0].mbr_type  = 0xEE;
    i = 0;
    while (i < gpt_part_count && new_mbr_part_count <= 3) {
       if ((gpt_parts[i].start_lba > new_mbr_parts[0].end_lba) && (gpt_parts[i].end_lba > 0) &&
           (gpt_parts[i].end_lba <= MAX_MBR_LBA) &&
           (gpt_parts[i].gpt_parttype->kind != GPT_KIND_BASIC_DATA) &&
           (gpt_parts[i].mbr_type != 0x83)) {
          copy_gpt_to_new_mbr(i, new_mbr_part_count);
          new_mbr_part_count++;
       }
       i++;
    } 
    for (i = 1; i < new_mbr_part_count; i++) {
       for (k = 0; k < mbr_part_count; k++) {
           if (mbr_parts[k].start_lba == new_mbr_parts[i].start_lba) {
               if (new_mbr_parts[i].mbr_type == 0)
                   new_mbr_parts[i].mbr_type = mbr_parts[k].mbr_type;
               new_mbr_parts[i].active = mbr_parts[k].active;
               break;
           } 
       } 
       if (new_mbr_parts[i].mbr_type == 0) {
          new_mbr_parts[i].mbr_type = 0xc0;
       } 
    } 
    sort_mbr(new_mbr_parts);
    for (iter = 0; iter < 3; iter++) {
        count_active = 0;
        for (i = 0; i < new_mbr_part_count; i++)
            if (new_mbr_parts[i].active)
                count_active++;
        if (count_active == 1)
            break;
        if (count_active == 0) {
            for (i = 0; i < new_mbr_part_count; i++) {
                if (((new_mbr_parts[i].mbr_type == 0x07 ||    
                      new_mbr_parts[i].mbr_type == 0x0b ||    
                      new_mbr_parts[i].mbr_type == 0x0c)) ||   (LBA)
                    (iter >= 1 && (new_mbr_parts[i].mbr_type == 0x83)) ||  
                    (iter >= 2 && i > 0)) {
                    new_mbr_parts[i].active = TRUE;
                    break;
                }
            }
        } else if (count_active > 1 && iter == 0) {
            if ((new_mbr_parts[0].mbr_type == 0xee || new_mbr_parts[0].mbr_type == 0xef) &&
                new_mbr_parts[0].active) {
                new_mbr_parts[0].active = FALSE;
            }
        } else if (count_active > 1 && iter > 0) {
            count_active = 0;
            for (i = 0; i < new_mbr_part_count; i++)
                if (new_mbr_parts[i].active) {
                    if (count_active > 0)
                        new_mbr_parts[i].active = FALSE;
                    count_active++;
                }
        }
    } 
}
static VOID generate_hybrid_mbr ( VOID ) { UINTN i , k , iter , count_active ; UINT64 first_used_lba ; new_mbr_part_count = 1 ; first_used_lba = ( UINT64 ) MAX_MBR_LBA + ( UINT64 ) 1 ; i = 0 ; do { if ( ( gpt_parts [ i ] . start_lba > 0 ) && ( gpt_parts [ i ] . end_lba > 0 ) && ( gpt_parts [ i ] . end_lba <= MAX_MBR_LBA ) && ( gpt_parts [ i ] . gpt_parttype -> kind == GPT_KIND_BASIC_DATA ) && ( gpt_parts [ i ] . mbr_type != 0x83 ) ) { copy_gpt_to_new_mbr ( i , new_mbr_part_count ) ; if ( new_mbr_parts [ new_mbr_part_count ] . start_lba < first_used_lba ) first_used_lba = new_mbr_parts [ new_mbr_part_count ] . start_lba ; new_mbr_part_count ++ ; } i ++ ; } while ( i < gpt_part_count && new_mbr_part_count <= 3 ) ; i = gpt_part_count - 1 ; while ( i < gpt_part_count && new_mbr_part_count <= 3 ) { if ( ( gpt_parts [ i ] . start_lba > 0 ) && ( gpt_parts [ i ] . end_lba > 0 ) && ( gpt_parts [ i ] . end_lba <= MAX_MBR_LBA ) && ( ( gpt_parts [ i ] . gpt_parttype -> kind == GPT_KIND_DATA ) || ( gpt_parts [ i ] . gpt_parttype -> kind == GPT_KIND_BASIC_DATA ) ) && ( gpt_parts [ i ] . mbr_type == 0x83 ) ) { copy_gpt_to_new_mbr ( i , new_mbr_part_count ) ; if ( new_mbr_parts [ new_mbr_part_count ] . start_lba < first_used_lba ) first_used_lba = new_mbr_parts [ new_mbr_part_count ] . start_lba ; new_mbr_part_count ++ ; } i -- ; } new_mbr_parts [ 0 ] . index = 0 ; new_mbr_parts [ 0 ] . start_lba = 1 ; new_mbr_parts [ 0 ] . end_lba = ( disk_size ( ) > first_used_lba ) ? ( first_used_lba - 1 ) : disk_size ( ) - 1 ; if ( new_mbr_parts [ 0 ] . end_lba > MAX_MBR_LBA ) new_mbr_parts [ 0 ] . end_lba = MAX_MBR_LBA ; new_mbr_parts [ 0 ] . mbr_type = 0xEE ; i = 0 ; while ( i < gpt_part_count && new_mbr_part_count <= 3 ) { if ( ( gpt_parts [ i ] . start_lba > new_mbr_parts [ 0 ] . end_lba ) && ( gpt_parts [ i ] . end_lba > 0 ) && ( gpt_parts [ i ] . end_lba <= MAX_MBR_LBA ) && ( gpt_parts [ i ] . gpt_parttype -> kind != GPT_KIND_BASIC_DATA ) && ( gpt_parts [ i ] . mbr_type != 0x83 ) ) { copy_gpt_to_new_mbr ( i , new_mbr_part_count ) ; new_mbr_part_count ++ ; } i ++ ; } for ( i = 1 ; i < new_mbr_part_count ; i ++ ) { for ( k = 0 ; k < mbr_part_count ; k ++ ) { if ( mbr_parts [ k ] . start_lba == new_mbr_parts [ i ] . start_lba ) { if ( new_mbr_parts [ i ] . mbr_type == 0 ) new_mbr_parts [ i ] . mbr_type = mbr_parts [ k ] . mbr_type ; new_mbr_parts [ i ] . active = mbr_parts [ k ] . active ; break ; } } if ( new_mbr_parts [ i ] . mbr_type == 0 ) { new_mbr_parts [ i ] . mbr_type = 0xc0 ; } } sort_mbr ( new_mbr_parts ) ; for ( iter = 0 ; iter < 3 ; iter ++ ) { count_active = 0 ; for ( i = 0 ; i < new_mbr_part_count ; i ++ ) if ( new_mbr_parts [ i ] . active ) count_active ++ ; if ( count_active == 1 ) break ; if ( count_active == 0 ) { for ( i = 0 ; i < new_mbr_part_count ; i ++ ) { if ( ( ( new_mbr_parts [ i ] . mbr_type == 0x07 || new_mbr_parts [ i ] . mbr_type == 0x0b || new_mbr_parts [ i ] . mbr_type == 0x0c ) ) || ( iter >= 1 && ( new_mbr_parts [ i ] . mbr_type == 0x83 ) ) || ( iter >= 2 && i > 0 ) ) { new_mbr_parts [ i ] . active = TRUE ; break ; } } } else if ( count_active > 1 && iter == 0 ) { if ( ( new_mbr_parts [ 0 ] . mbr_type == 0xee || new_mbr_parts [ 0 ] . mbr_type == 0xef ) && new_mbr_parts [ 0 ] . active ) { new_mbr_parts [ 0 ] . active = FALSE ; } } else if ( count_active > 1 && iter > 0 ) { count_active = 0 ; for ( i = 0 ; i < new_mbr_part_count ; i ++ ) if ( new_mbr_parts [ i ] . active ) { if ( count_active > 0 ) new_mbr_parts [ i ] . active = FALSE ; count_active ++ ; } } } }
Generate a hybrid MBR based on the current GPT.
Generate a hybrid MBR based on the current GPT .
// Copy partitions in three passes.... // First, do FAT and NTFS partitions.... /* Within MBR limits */ /* MS Basic Data GPT type code */ /* Not containing Linux filesystem */ // Second, do Linux partitions. Note that we start from the END of the // partition list, so as to maximize the space covered by the 0xEE // partition if there are several Linux partitions before other hybridized // partitions. // Note that gpt_part_count can't be 0; filtered by check_gpt() // if too few GPT partitions, i loops around to a huge value // while // Third, do anything that's left to cover uncovered spaces; but this requires // first creating the EFI protective entry, since we don't want to bother with // anything already covered by this entry.... // while // find matching partitions in the old MBR table, copy undetected details.... // keep type if not detected // keep active flag // if // for (k...) // final fallback: set to a (hopefully) unused type // if // for (i...) // make sure there's exactly one active partition // check // set active on the first matching partition // NTFS // FAT32 // FAT32 (LBA) // Linux // too many active partitions, try deactivating the ESP / EFI Protective entry // too many active partitions, deactivate all but the first one // for