第12章
プログラミングを使用して MBR を読み取り、変更する
マスター ブート レコード (MBR) またはマスター パーティション テーブル (MPT)
マスター ブート レコード (MBR) またはマスター パーティション テーブル (MPT) と呼ばれるものは、FDISK.EXE DOS コマンドを実行することによってハード ディスク上に作成されます。
MBR には、ハード ディスクからアクティブ (またはブート) パーティションを読み込んで実行するための小さなプログラムが含まれています。マスター ブート レコードには、開始セクター、終了セクター、パーティション サイズなど、ハード ディスク上の 4 つのプライマリ パーティションすべてに関する情報が含まれています。
MBR は絶対セクター 0、つまりシリンダー 0、ヘッド 0、セクター 1 に配置されており、ディスク上に複数のパーティションがある場合は、拡張パーティションの各ボリュームの先頭に拡張マスター ブート レコードが配置されます。
詳細な説明については、この本の前半で説明した「ディスクと OS への論理的アプローチ」の章を参照してください。
マスターブートレコードフォーマット
ハードディスクを複数の論理ドライブに分割することができ、通常、DOS は独自のドライブ文字を割り当てます。一度にアクティブ (またはブート) パーティションとしてマークできるパーティションは 1 つだけです。

マスター ブート レコードには、プライマリ パーティション テーブル内のエントリが 4 つまでという制限があります。ただし、拡張 MBR の場所は、拡張パーティション テーブルを含む MBR を使用して取得できます。拡張パーティション テーブルは、ブート コードが含まれず、446 バイトの領域が通常ブート コード用に予約されて空のままになっていることを除いて、プライマリ パーティション テーブルと同じ形式です。
マスター ブート レコードの 512 バイト全体は、次の表に示すように分類されます。

すべての拡張パーティションは、拡張パーティション エントリによって予約された領域に存在する必要があります。拡張パーティションのうち 2 つだけを使用することを意図しており、1 つ目は通常のパーティションとして、2 つ目は別の拡張パーティション (存在する場合) として使用されます。
したがって、1 つのマスター パーティション テーブルを使用すると、その隣に別の拡張マスター パーティション テーブルがある場合は、その場所を取得できます。
パーティションテーブルエントリの形式
MBR 内の任意のパーティションのパーティション テーブル エントリ形式を次の表に示します。任意の MBR の各パーティション エントリは、特定の意味を持つ次のバイトに分割できます。

MBRパーティションテーブルを読み取るプログラムの作成
以下は、MBR パーティション テーブルから 4 つのパーティション エントリすべてを読み取るプログラムです。このプログラムは、MBR パーティション テーブルに記録されているパーティション情報のすべてのパラメータを表示します。
プログラムのエンコーディングは次のようになります。
/* MBR パーティション テーブルを読み取るプログラム*/
# <bios.h> をインクルードする
/*パーティションテーブルからパーティションエントリを読み取るための構造体*/
構造セクション
{
unsigned char ブート可能; /* セクションのアクティブバイト */
unsigned char start_side ;/* 開始ヘッド */
符号なし整数 start_sec_cyl ; /* 組み合わせ
開始セクターと
シリンダー番号 */
符号なしchar型パーツタイプ; /* ファイルシステム
インジケータバイト */
符号なしchar end_side; /* ヘッダー終了 */
符号なし整数 end_sec_cyl ; /* 組み合わせ
開始セクターと
シリンダー番号 */
符号なしロングpart_beg; /* 相対セクター
番号 */
符号なし長整数; /* セクションの長さ
セクター */
} ;
/* MBR を読み取るための構造体*/
構造の一部
{
符号なしchar型master_boot[446]; /* IPL (初期
プログラムローダー)*/
構造体パーティションpt[4]; /* パーティションテーブル */
最後の2つを整数にする; /* マジックナンバー */
} ;
構造 p の一部。
無効な main()
{
clrscr();
/*最初のハードドライブの最初のセクターを読み取ります*/
バイオディスク ( 2, 0x80, 0, 0, 1, 1, &p ) ;
画面(); /* MBR情報を表示
パーティションテーブル */
得る();
}
/* MBR パーティション テーブルに関する情報を表示する関数*/
画面()
{
符号なし整数 s_sec、s_trk、e_sec、e_trk、i、t1、t2 ;
文字タイプ[20]、ブート[5];
printf("\n\nパート。初期ロード場所
最終場所相対量");
printf("\nタイプ サイド シリンダ セクター
サイド シリンダー セクター セクター セクター\n");
( i = 0 ; i <= 3 ; i++ ) の場合
{
p.pt[i].bootable == 0x80 の場合
strcpy ( ブート、「はい」 ) ;
それ以外
strcpy ( ブート、「いいえ」 ) ;
スイッチ ( p.pt[i].parttype )
{
0x00の場合:
strcpy ( type, "未使用" ); break ;
ケース0x1:
strcpy ( type, "FAT12" ); break ;
ケース0x2:
strcpy ( type, "Xenix" ); break ;
ケース0x3:
strcpy ( type, "Xenix:usr" ); break ;
ケース0x4:
strcpy ( type, "FAT16<32M" ); break ;
ケース0x5:
strcpy ( type, "DOS-Ext." ); break ;
ケース 0x6:
strcpy ( type, "FAT16>32M" ); break ;
ケース 0x7:
strcpy ( type, "NTFS" ); break ;
ケース 0x0b :
strcpy ( type, "FAT32" ); break ;
ケース 0x0c :
strcpy ( type, "FAT32-LBA" ); break ;
0x0dの場合:
strcpy ( type, "VFAT16" ); break ;
ケース 0x0e :
strcpy ( type, "VFAT16-LBA" ); break ;
0x0fの場合:
strcpy ( type, "VFAT EXT" ); break ;
ケース0x17:
strcpy ( type, "HPFS" ); break ;
ケース 0x81 :
strcpy ( type, "Old LINUX" ); break ;
ケース 0x82 :
strcpy ( type, "LinuxSwap" ); break ;
ケース0x83:
strcpy ( type, "LinuxNative " ); break ;
ケース 0x85 :
strcpy ( type, "Linux Ext." ); break ;
デフォルト :
strcpy ( type, "Unknown" ); break ;
}
s_sec = ( p.pt[i].start_sec_cyl & 0x3f ) ; /* 開始
セクターの
パーティション */
t1 = ( p.pt[i].start_sec_cyl & 0xff00 ) >> 8 ;
t2 = ( p.pt[i].start_sec_cyl & 0x00c0 ) << 2 ;
s_trk = t1 | t2 ; /* 始動シリンダ */
e_sec = ( p.pt[i].end_sec_cyl & 0x3f ) ; /*終了セクター */
t1 = ( p.pt[i].end_sec_cyl & 0xff00 ) >> 8 ;
t2 = ( p.pt[i].end_sec_cyl & 0x00c0 ) << 2 ;
e_trk = t1 | t2 ; /* シリンダ終了 */
printf ( "\n%6s %3s", type, boot ) ;
printf ( "%4d %6d %8d", p.pt[i].start_side, s_trk,s_sec );
printf ( "%7d %6u %8u", p.pt[i].end_side, e_trk, e_sec );
printf ( " %10lu %10lu", p.pt[i].part_beg,
p.pt[i].plen ) ;
}
0を返します。
}
プログラムの出力によって提供される情報は、以下のように表示されます。

コーディングに関するコメント:
構造パーティションは、MBR のパーティション テーブル内のパーティションのパーティション エントリのさまざまなパラメータを読み取るために使用されます。構造部分は、MBR 情報を読み取るために使用されます。
関数display() は、 MBR パーティション テーブル パラメータの情報を画面に表示します。プログラムの出力を見ると、開始シリンダ番号と終了シリンダ番号、およびセクター番号が次のように表示されます。
開始セクター = 1
始動シリンダ = 0
終了セクター = 63
終了シリンダー = 701
これらのセクター番号とシリンダー番号は、2 つのバイトの組み合わせから計算されます。次の表は、これらの番号の計算方法を示しています。

したがって、パーティションの開始 CHS は 0-0-1 です。
同様に、パーティションの終了シリンダとセクター番号のエンコーディングは次の表に示されています。

したがって、パーティションの終了 CHS は 701-254-63 になります。
すべての論理パーティションとその情報を検索するプログラム
先ほど説明したプログラムは、MBR のパーティション テーブルからパーティション情報を読み取るものでした。ただし、MBR を読み取るだけでは、ディスクの拡張パーティションにある他の論理パーティションの情報を取得することはできません。
マスター ブート レコードには、マスター パーティション テーブル内のエントリが 4 つまでという制限があることはすでに説明しました。ただし、拡張マスター ブート レコードの場所は、メイン パーティション テーブルとまったく同じ形式を持つ拡張パーティション テーブルを含むマスター ブート レコードの助けを借りて取得できます。
すべての拡張パーティションは、拡張パーティション エントリによって予約されたスペース内に存在する必要があります。拡張パーティションのうち 2 つだけを使用することになっています。1 つ目は通常のパーティションとして、2 つ目は存在する場合は別の拡張パーティションとして使用されます。
したがって、1 つのマスター パーティション テーブルの助けを借りて、その隣に別の拡張マスター パーティション テーブル (存在する場合) の場所を取得できます。
次のプログラムは、ディスクからMBR と拡張 MBR を読み取り、すべての論理パーティションとそのパーティション エントリ情報を検索するためのものです。プログラムのコーディングは次のとおりです。
/*ディスク内に存在するすべての論理パーティションのパラメータを読み取るプログラム*/
#include<dos.h>
buffer[512]、report_par[20]があります。
符号なしドライブ番号 =0x80;
符号なしlong star_sec[20]、秒;
/* readabsolutesectors 関数で使用されるディスク アドレス パケット形式の構造*/
構造体ディスクアドレスパケット
{
char packetsize ; /* パケットのサイズ、通常は 10H */
char reserved ; /* 予約済み (0) */
int blockcount; /* 転送するブロック数 */
char far *bufferaddress; /* 転送先のアドレス
バッファ */
unsigned long blocknumber[2] ; /* 開始絶対値
ブロック番号 */
} ;
void main()
{
偶数ではない、i;
clrscr();
偶数 = 0;
すべてのパーティション情報 (star_sec、&no_par、&sec、バッファ、
レポート_par);
printf(" \n\n ディスク内のパーティションの合計数 = %d\n ",
偶数ではありません);
(i=0;i<no_par;i++) の場合
{
printf("\n パーティションの開始セクター番号 %d =
%lu " , i+1, star_sec[i]);
}
printf("\n");
getch();
}
プログラムの出力は次のように表示されます。
パーティション 1 - FAT32
パーティション 2 - FAT32
パーティション 3 - FAT32
ディスク内のパーティションの合計数 = 3
パーティション 1 の開始セクター番号 = 63
パーティション 2 の開始セクター番号 = 11277693
パーティション 3 の開始セクター番号 = 25623738
コーディングに関するコメント:
構造体diskaddrpacket は、readabsolutesectors 関数によって使用されるディスク アドレス パケット形式を読み取るために使用されます。
All_partition_information( )関数は、パーティション エントリからすべてのパーティションのすべてのパラメータを検索するために使用されます。
このプログラムでは、ディスク内のすべての使用可能な論理パーティションのファイル システムと相対セクター情報のみを表示していますが、関数All_partition_information( )とさらにいくつかの printfを使用して、パーティション情報の他のパラメーターの情報も印刷できます。
関数のコーディングは次のとおりです。
/*パーティションエントリを読み取り、すべての論理パーティションの情報を検索する関数*/
All_partition_information( 符号なしlong *star_sec,
符号なし*no_par、
long *sec、char *buffer、
符号なしchar *report_par )
{
符号なしロング fat_check;
符号なし long *sectors_part;
静的ロング se_p;
int temp_var1、active_offset、active_pos=0、i、extended_pos=0、partloc1;
符号なしロングb_sec、se;
符号なしcharアクティブ_par;
長い相対秒;
長い no_sectors;
if(*秒==0 || *秒==1)
0 を返します。
する{
se=*秒;
/ * *sec で指定された絶対セクターを読み取ります*/
絶対セクターを読み取ります (ドライブ番号、*秒、1、バッファ)。
/* *****アクティブパーティションをチェック***** */
if(*sec==se && *no_par==0) /*プライマリの場合
パーティション */
{
*秒= se = 0;
(アクティブオフセット=446; アクティブオフセット<=494; アクティブオフセット+=16)
{
active_par=バッファ[active_offset];
if(active_par==0x80) /* アクティブかどうかチェック
パーティション */
壊す;
それ以外
active_pos++; /* アクティブの位置
パーティション */
}
/*拡張パーティション用*/
(アクティブオフセット=450; アクティブオフセット<=511; アクティブオフセット+=16)
{
active_par=バッファ[active_offset];
アクティブ_par==0x05 | アクティブ_par==0x0Fの場合
/*拡張パーティションをチェック*/
壊す;
それ以外
Extended_pos++; /*拡張位置
パーティション */
}
アクティブ位置==4の場合
アクティブ位置=1;
拡張位置==4の場合
拡張位置=1;
パートロケーション1 = 0x1C0 +拡張位置* 16;
}
それ以外
{
アクティブ位置=0;
拡張位置=1;
パートロケーション1 = 0x1D0;
もし(se_p!=0)
{
*sec=se=se_p; /*拡張の開始
パーティション */
}
}
/*パーティション内の相対セクター*/
relative_sec= *(unsigned long *)(バッファ+454+active_pos*16);
/*パーティション内のセクター数*/
no_sectors=*(long *)(バッファ+458+アクティブ位置*16);
/*ファイルシステムインジケーターバイトを識別する*/
if( バッファ[0x1C2+active_pos*16]==0x04 ||
バッファ[0x1C2+アクティブ位置*16]==0x05 ||
バッファ[0x1C2+アクティブ位置*16]==0x06 ||
バッファ[0x1C2+アクティブ位置*16]==0x0B ||
バッファ[0x1C2+アクティブ位置*16]==0x0C ||
バッファ[0x1C2+アクティブ位置*16]==0x0E ||
バッファ[0x1C2+アクティブ位置*16]==0x0F ||
バッファ[0x1C2+アクティブ位置*16]==0x07)
{
スイッチ(バッファ[0x1C2+active_pos*16])
{
/* NTFS パーティションの場合 */
ケース0x07: report_par[*no_par]='N';
printf("\n パーティション -%d = NTFS",
*偶数ではない+1);
壊す;
/* FAT32 パーティションの場合*/
ケース0x0B:
ケース0x0C: report_par[*no_par]='3';
printf("\n パーティション -%d = FAT32",
*偶数ではない+1);
壊す;
/* FAT16 パーティションの場合*/
ケース0x04:
ケース0x06:
ケース0x0E: report_par[*no_par]='1';
printf("\n パーティション -%d = FAT16",
*偶数ではない+1);
壊す;
} // スイッチの終了
b_sec=*秒+相対秒;
sectors_part[*no_par]=no_sectors; /* パーティションのセクター数を格納する配列 */
} //if条件の終了
それ以外
{ /* パーティションインジケータが一致しない場合 */
if(*sec==0)
{ no_par = 0;
壊す;
}
if((fat_check!=0x3631)&&(fat_check!=0x3233))
b_sec=*sec=0;
}
if((b_sec!=0)&&(sec!=0))
{
star_sec[*no_par]=b_sec;
(*偶数ではない)++;
}
それ以外
壊す;
/*拡張パーティションが存在するかどうかを確認*/
if(バッファ[0x1C2+拡張位置*16]==0x05 ||
バッファ[0x1C2+拡張位置*16]==0x0F)
{
temp_var1=(符号なし)バッファ[partloc1];
*sec=temp_var1 & 0x003F; /* セクターの
延長
パーティション */
if(*sec!=0)
{
se_p=se+相対秒+セクターなし;
*sec=se_p;
}
それ以外
{ *秒=-1;
壊す;
}
} //if文の終了
それ以外
{
(秒>0の場合)
*秒=-1;
壊す;
}
} while(1); // do-whileループの終了
/*セクター 0 上の他の非アクティブなプライマリ パーティションをチェックします*/
if(*sec==0)
{
(i=0;i<4;i++) の場合
{
アクティブ_par=バッファ[446+i*16];
/*ファイルシステムインジケータバイトを識別します*/
if((バッファ[0x1C2+i*16]==(文字)0x06 ||
バッファ[0x1C2+i*16]==(文字)0x0B ||
バッファ[0x1C2+i*16]==(文字)0x0C ||
バッファ[0x1C2+i*16]==(文字)0x07 ||
バッファ[0x1C2+i*16]==(文字)0x0E ||
バッファ[0x1C2+i*16]==(文字)0x04) && active_par!=0x80)
{
スイッチ(バッファ[0x1C2+active_pos*16])
{
/* NTFS パーティションの場合*/
ケース0x07: report_par[*no_par]='N';
printf("\n パーティション -%d = NTFS",
*偶数ではない+1);
壊す;
/* FAT32 パーティションの場合*/
ケース0x0B:
ケース0x0C: report_par[*no_par]='3';
printf("\n パーティション -%d = FAT32",
*偶数ではない+1);
壊す;
/* FAT16 パーティションの場合*/
ケース0x04:
ケース0x06:
ケース0x0E: report_par[*no_par]='1';
printf("\n パーティション -%d = FAT16",
*偶数ではない+1);
壊す;
} // スイッチの終了
/*パーティションの相対セクター数*/
relative_sec=*(long *)(バッファ+454+i*16);
no_sectors=*(long *)(buffer+458+i*16); /* セクター数
セクター
パーティション*/
sectors_part[*no_par]=no_sectors; /* 格納する配列
数
セクターの
パーティション */
*sec=star_sec[*no_par]=相対秒;
(*偶数ではない)++;
}
} // for(i=0;i<4;i++) のループ終了
} //if(*sec==0) のループ終了
戻る;
}
コーディングに関するコメント:
この関数は、MBR からパーティション情報の読み取りを開始し、必要に応じて拡張 MBRを読み取ります。関数 readabsolutesectors は、*sec で指定された絶対セクターを読み取ります。
sectors_part[*no_par]はパーティションのセクター数を格納する配列です。パーティション番号は0から始まる*no_parで指定されます。
no_sectors はパーティション内のセクター数であり、relative_sec はそのパーティションの相対セクター番号です。
star_sec[*no_par]はパーティションの開始セクター番号を格納する配列です。パーティション番号は0から始まる*no_parで指定されます。
star_cyl、star_hea、star_sec は、CHS の観点から各パーティションの開始情報を保持する配列です。star_cyl には開始シリンダの情報が保存され、star_hea には開始ヘッドの情報が保存され、star_sec にはパーティションの開始セクタの情報が保存されます。
readabsolutesectors 関数の説明については、この本の前の章を参照してください。
プログラミングによるMBRの変更
MBR パーティション テーブル エントリの値を変更する方法を示すサンプル プログラムを以下に示します。このプログラムは、MBR パーティション テーブルの 2 番目のパーティション エントリの値を変更します。
プログラムのコーディングは以下の通りです。
/* MBR のパーティション テーブル エントリの値を変更するプログラム*/
# <bios.h> をインクルードする
/*パーティションテーブルからパーティションエントリを読み取るための構造体*/
構造体パーティション
{
unsigned char bootable ; /* アクティブパーティション
バイト */
unsigned char start_side ; /* 開始ヘッド */
unsigned int start_sec_cyl; /* の組み合わせ
開始セクターと
シリンダー番号 */
unsigned char parttype ; /* ファイルシステム
インジケータバイト */
unsigned char end_side ; /* 終了ヘッド */
unsigned int end_sec_cyl; /* の組み合わせ
開始セクターと
シリンダー番号 */
unsigned long part_beg ; /* 相対セクター
番号 */
unsigned long plen; /* パーティションの長さ
セクター */
} ;
/* MBR を読み取るための構造体*/
構造体部分
{
unsigned char master_boot[446] ; /* IPL (初期
プログラムローダー)*/
structpartitionpt[4]; /* パーティションテーブル*/
int lasttwo ; /* マジックナンバー */
} ;
構造体部分 p ;
void main()
{
符号なし整数 t1,t2;
clrscr();
バイオディスク ( 2, 0x80, 0, 0, 1, 1, &p ) ;
display(); /* パーティションを表示
テーブル情報 */
getch();
/* MBRのパーティションテーブルから2番目のパーティションエントリのパーティション情報を次の値で変更すると仮定します*/
p.pt[1].bootable = 0x80; /* アクティブブートパーティション */
p.pt[1].parttype = 0x7; /* NTFSパーティション */
p.pt[1].start_side = 0; /* 開始ヘッド =0 */
1. エンドサイド/* ヘッダー終了 == 31 */
p.pt[1].part_beg = 808416;/* 相対セクター = 808416 */
フルサイズ/* パーティション内のセクターの総数 = 405216 */
/*新しい情報をMBRに書き込む*\
/* MBRパーティションテーブルに値を書き込むには、以下のbiosdisk関数のコメントを解除します*/
// バイオディスク ( 3, 0x80, 0, 0, 1, 1, &p ) ;
画面(); /* 表示が変更されました
情報 */
得る();
}
コーディングコメント:
上記のプログラムは、MBR パーティション テーブル エントリの値を変更する方法を示すサンプル プログラムです。拡張パーティション内にある論理パーティションのパーティション エントリ値を変更する場合は、拡張 MBR パーティション テーブルの値を変更する必要があります。
パーティション テーブル エントリを変更するためにここで指定された値は、変更方法を示すためだけのものです。無効な値や非論理的な値でパーティション テーブルを変更しないでください。その結果、セクション全体にアクセスできなくなる可能性があります。
構造セクションはパーティション テーブルからパーティション レコードを読み取るために使用され、構造部分は MBR を読み取るために使用されます。パーティション テーブルを変更するには、biosdisk()関数のコメントを解除します。
パーティションの開始値と終了値、セクター番号とシリンダー番号を変更する場合は、この章の冒頭で説明したMBR パーティション テーブルを読み取って表示するプログラムのコメントに記載されているように値を計算します。