第10章
破損したディスクからデータを回復する
破損したフロッピーディスクからデータを回復する
フロッピー ディスクは、最も信頼性の低いデータ保存ソースの 1 つです。コンピュータ システムを使用している組織を訪問し、フロッピー ディスクによって発生する問題について従業員に尋ねると、多くの場合、問題は組織の従業員がフロッピー ディスクに重要なデータを保存していたため、フロッピー ディスクがコンピュータで読み取れなくなり、次のようなメッセージが画面に表示されることであると聞かされるでしょう。
「ディスクを読み取れません」
「トラック 0 が不良です」
「ディスクまたは容量が無効です」
「ディスクがフォーマットされていません。今すぐフォーマットしますか?
これは、コンピュータ システムやフロッピー ディスクを使用する組織にとって日常的な問題です。破損したフロッピー ディスク上で失われたと思われるデータのバックアップが作成されていないか、バックアップが利用できないことが判明した場合、問題は重大になります。
最大の問題は、重要な情報をフロッピー ディスクにバックアップする場合、ウイルス攻撃を克服するためにウイルス対策プログラム ディスクを復元する場合、またはブート レコードやその他のバックアップ (複数のオプションがある場合があります) をフロッピー ディスクにバックアップする場合に、フロッピー ディスクからバックアップを再利用しようとすると、読み取りエラーが発生することです。
このような場合、重要な情報やデータを失うリスクがあり、場合によっては、コンピュータの起動情報のバックアップや回復プログラム、ウイルス攻撃救助プログラムなどの不足を感じた場合、フロッピーディスクに保存された情報が不足しているため、現時点でコンピュータで読み取ることができないため、OS障害という形で大きなデータ損失を被る場合があります。
このような場合、最も重要な要件は、コンピュータ システムが障害があると認識したフロッピー ディスクからデータを回復することとなります。
フロッピーディスクが読み取れないのはなぜですか?
フロッピー ディスクでこのようなエラー メッセージが表示される最も一般的な問題は、フロッピー ディスクの DOS ブート レコード (DBR) が破損していることです。DBR は、コンピューターがフロッピー ディスクの論理 ID を認識するのに役立ちます。
DBR は、トラック 0、ヘッド 0、セクター 1 に保存される小さなプログラムで、次のようなフロッピー ディスクに関する重要な情報が含まれています。
- セクターあたりのバイト数
- クラスターあたりのセクター
- FATの数
- ルートディレクトリ等の最大数
フロッピー ディスクには論理パーティション システムがないため、フロッピー ディスクには MBR が存在しません。フロッピー ディスクの最初のセクターには DBR が含まれています。これは、ハードディスクとフロッピー ディスクの論理構造を比較した場合の主な違いでもあります。
任意のディスク編集プログラムを使用してフロッピー ディスクのブート セクター情報を読み取ると、下の画像のような情報が表示されます。
次の図は、1.44 MB、3½ インチのフロッピー ディスク上の 512 バイトの DBR 情報を示しています。

この情報が何らかの理由で破損したり、読み取り不能になったりすると、フロッピー ディスクから読み取りエラー メッセージが生成されます。これは、ディスクの最初のセクターの物理的または論理的な損傷が原因である可能性があります。
論理的な破損には、ディスケットの最初のセクターの情報が変更された場合、論理的に破損したセクターがある場合、またはディスケットのDBR が他の何らかの理由で破損している場合が含まれます。
フロッピー ディスクの最初のセクターに物理的な不良セクターがある場合 (つまり、セクター 1 が物理的に損傷している場合)、物理的な損傷が発生したと想定されます。フロッピー ディスクのトラック 0 に複数の不良セクタがあることがわかった場合、問題はさらに深刻になります。
回復方法
両方の損傷原因を学んだので、問題を理解できたと思います。論理的な破損からデータを回復するのはそれほど難しくありませんが、物理的な破損から回復するにはもう少しの労力が必要です。
方法 – 1
新しいフロッピー ディスクの起動可能なイメージを保存します。
問題が論理的なものであれば、データを回復する方法がわかります。必要なのは、同じサイズと容量の別のフロッピーから適切なブート レコードを取得し、それを読み取り不能なフロッピーの最初のセクターに貼り付けることだけです。問題は不良ブート レコードによって発生しましたが、今は機能するはずです。
この手順には、読み取り不可能なフロッピーからデータを回復するための 2 つのステップがあります。
- 良質なフロッピーのDOSブートレコードのイメージを作成する
- 読み取り不可能なフロッピーの最初のセクターにブートイメージを貼り付ける
良質なフロッピーのDOSブートレコードのイメージを作成する
新しいフロッピーのブート レコードのイメージを保存するには、プログラムは次の 3 つのタスクを実行する必要があります。
- 正常なフロッピーの最初の512バイトを正確に読み取ります
- 読み取り操作が成功したかどうかを確認する(最も重要)
- これらの512バイトを指定されたファイル名と宛先パスに保存します
フロッピーのセクターは 512 バイトで、セクターの正確なイメージをコピーする必要があります。フロッピーに対して何らかの操作を実行する場合、操作が成功したかどうかを確認することが最も重要かつ必要な手順です。
新品のフロッピー ディスクでも初期化の問題が発生する可能性があります。そのため、フロッピー ディスクで操作を実行する場合のほとんどの場合、最初にプログラミングでリセット ディスク操作(INT 13H の機能 00 H) を使用してフロッピー ディスクの初期化を実行します。
初期化後でも、最近挿入したフロッピー ディスクまたは交換したフロッピー ディスクで読み取りエラーが発生する場合は、プログラムを再度実行することをお勧めします。おそらく今回は機能するでしょう。
次のプログラムは、これらの指定されたタスクを実行します。どのように進行するかを見てみましょう。
/*新しいフロッピーディスクからブートイメージをファイルに保存します*/
#include <bios.h>
#include <stdio.h>
int メイン(void)
{
構造体 diskinfo_t dinfo;
ユニオン REGS regs;
int 結果;
整数カウント=0、i;
char fname[80];
静的char dbuf[512];
ファイル *fp;
dinfo.drive = 0x00; /* A のドライブ番号: */
dinfo.head = 0; /* ディスクヘッド番号 */
dinfo.track = 0; /* トラック番号 */
dinfo.sector = 1; /* セクター番号 */
dinfo.nsectors = 1; /* セクター数 */
dinfo.buffer = dbuf; /* データ バッファ */
clrscr();
gotoxy(10,3);cprintf("ファイル名とパスを入力してください
ブートイメージを保存する");
ゴトキシ(5,5);
取得(fname);
fp = fopen(fname、"wb");
if((fp=fopen(fname,"wb"))==NULL)
{
ハイビデオ();
gotoxy(10,10);cprintf("ファイルを作成できませんでした");
getch();
終了(0);
}
ゴトキシ(10,9);
cprintf("フロッピーディスクドライブから読み取ろうとしています:\n");
///ディスクシステムを初期化します\\\
(i=0; i<3; i++) の場合
{
regs.h.ah = 0x00; /* ディスクシステムをリセット */
regs.h.dl = 0x00; /* フロッピーディスク a: */
int86(0x13, ®s, ®s);
}
結果 = _bios_disk(_DISK_READ, &dinfo);
((結果 & 0xff00) == 0)の場合
{
while(カウント<512)
{
fprintf(fp,"%c",dbuf[count] & 0xff);
カウント++;
}
fp を閉じる
gotoxy(10,14);cprintf("フロッピーディスクドライブからディスクを読み取りました
: 成功しました。\n");
}
それ以外
{
ゴトキシ(10,14);
cprintf("ドライブ A を読み取れません。ステータス = 0x%02x\n", 結果);
スイッチ(結果)
{
0x00の場合:
cprintf("\n\n ステータス:エラーなし!! ");
壊す;
ケース0x01:
cprintf("\n\n ステータス:不正なコマンド");
壊す;
ケース0x02:
cprintf("\n\n ステータス:アドレスマークが見つかりません");
壊す;
ケース0x03:
cprintf("\n\n ステータス:書き込み禁止のディスクに書き込もうとしました");
壊す;
ケース0x04:
cprintf("\n\n ステータス:セクターが見つかりません");
壊す;
ケース0x06:
cprintf("\n\n ステータス:最後の操作以降にディスクが変更されました");
壊す;
ケース0x08:
cprintf("\n\n ステータス:ダイレクト メモリ アクセス (DMA) オーバーラン");
壊す;
ケース0x09:
cprintf("\n\n ステータス: 64K 境界を越えて DMA を実行しようとしています");
壊す;
ケース 0x0C:
cprintf("\n\n ステータス:メディアタイプが見つかりません");
壊す;
ケース0x10:
cprintf("\n\n ステータス:ディスク読み取り時の CRC/ECC が不良です");
壊す;
ケース0x20:
cprintf("\n\n ステータス:コントローラーが失敗しました");
壊す;
ケース0x31:
cprintf("\n\n ステータス:ドライブにメディアがありません (IBM/MS INT 13H 拡張) ");
壊す;
ケース0x32:
cprintf("\n\n ステータス: CMOS に保存されているドライブ タイプが正しくありません (Compaq) ");
壊す;
ケース0x40:
cprintf("\n\n ステータス:シーク操作に失敗しました");
壊す;
ケース0x80:
cprintf("\n\n ステータス:添付ファイルが応答しませんでした(ディスクがタイムアウトしました) ");
壊す;
ケース0xB0:
cprintf("\n\n ステータス:ボリュームがドライブ内でロックされていません (INT 13H 拡張) ");
壊す;
ケース0xB1:
cprintf("\n\n ステータス:ドライブ内のボリュームがロックされています (INT 13H 拡張) ");
壊す;
ケース0xB2:
cprintf("\n\n ステータス:ボリュームは削除できません (INT 13H 拡張) ");
壊す;
ケース0xB3:
cprintf("\n\n ステータス:ボリュームは使用中 (INT 13H 拡張) ");
壊す;
ケース0xB4:
cprintf("\n\n ステータス:ロックカウントを超えました (INT 13H 拡張) ");
壊す;
ケース0xB5:
cprintf("\n\n ステータス:有効な排出要求が失敗しました (INT 13H 拡張) ");
壊す;
デフォルト: cprintf("\n\n ステータス:フロッピー エラーの不明ステータス コード");
}
}
0を返します。
}
プログラムコーディングに関するコメント:
前述のプログラムコーディングでは、基本的に次のタスクを段階的に実行していきます。
- dinfo は、_bios_disk 関数によって実行される操作に必要なパラメータの情報を含む diskinfo_t 構造体を指します。
- ディスクの最初のセクターを読み取りたいので、セクターの場所は次のようになります。
パラメータ |
それが意味するもの |
dinfo.ドライブ = 0x00 |
フロッピーディスクドライブであるドライブ0 ( a :)を示します。 |
dinfo.head = 0 |
ヘッド番号0を指します |
dinfo.track = 0 |
トラック0を指します |
dinfo.セクター = 1 |
フロッピーの最初のセクター、つまりセクター1 |
dinfo.セクター = 1 |
読み取り操作で考慮するセクター数 = 1 |
dinfo.バッファ = dbuf |
操作用のデータバッファ |
- ユーザーが指定したファイル名とパスのファイル ストリームを開き、正確に 512 バイトのブート イメージ情報を保存します。ファイル名とパスは、文字配列 fname に保存されます。
- 割り込み 13H (関数 00h) を使用してディスク システムを初期化します。ここで、regs.h.ah = 0x00 は関数 00 H を指し、regs.h.dl = 0x00 はフロッピーに使用されます。また、int86(0x13, ®s, ®s) は MS-DOS 割り込みサービス INT 13 H を呼び出します。
- _bios_disk(_DISK_READ, &dinfo) はフロッピー ディスクの指定されたセクターを読み取ります。
- 返されたステータスは結果に保存され、操作が成功した場合にメッセージを表示したり、エラーが発生した場合に画面にエラー メッセージを表示したりするために使用されます。

読み取り不可能なフロッピーの最初のセクターにブートイメージを貼り付ける
ファイルから読み取り不可能なフロッピーの最初のセクターにブート イメージを貼り付けるには、プログラムで次の 3 つの主なタスクを実行する必要があります。
- 以前に保存したファイルから、新しいフロッピーのブート レコードの正確な 512 バイト情報を読み取ります。
- この情報を、現在読み取り不可能なフロッピーの最初のセクターに書き込みます。
- 書き込み操作が正常に完了したかどうかを確認します (最も重要)。
フロッピーのセクターは 512 バイトなので、正確なブート イメージをセクターに貼り付ける必要があります。フロッピーに対して何らかの操作を行った場合、その操作が成功したかどうかを確認することが最も重要かつ必要な手順です。
操作中にフロッピー ディスクの初期化の問題が発生する可能性があるため、ディスク システムをリセットしてディスクを初期化する必要があります(INT 13H の機能 00H を使用)。
初期化後でも、最近挿入したフロッピー ディスクまたは交換したフロッピー ディスクで読み取りエラーが発生する場合は、プログラムを再度実行することをお勧めします。おそらく今回は機能するでしょう。
次のプログラムは、これらの指定されたタスクを実行します。どのように進行するかを見てみましょう。
/*読み取り不可能なフロッピーにブートイメージをロードする*/
#include <bios.h>
#include <stdio.h>
int メイン(void)
{
構造体 diskinfo_t dinfo;
ユニオン REGS regs;
int 結果;
整数カウント=0、i;
char fname[80];
char dbuf[512];
ファイル *fp;
clrscr();
gotoxy(5,3);cprintf("フロッピーのブートイメージが保存されているファイル名とパスを入力してください");
ゴトキシ(5,5);
取得(fname);
fp = fopen(fname、"rb");
if((fp=fopen(fname,"rb"))==NULL)
{
ハイビデオ();
gotoxy(10,10);cprintf("ファイルを開けませんでした");
getch();
終了(0);
}
ゴトキシ(10,9);
cprintf("フロッピーディスクドライブの回復を試行しています:\n");
///ディスクシステムを初期化します\\\
(i=0; i<3; i++) の場合
{
regs.h.ah = 0x00; /* ディスクシステムをリセット */
regs.h.dl = 0x00; /* フロッピーディスク a: */
int86(0x13, ®s, ®s);
}
while(カウント<512)
{
fscanf(fp,"%c",&dbuf[count]);
カウント++;
}
dinfo.drive = 0x00; /* A のドライブ番号: */
dinfo.head = 0; /* ディスクヘッド番号 */
dinfo.track = 0; /* トラック番号 */
dinfo.sector = 1; /* セクター番号 */
dinfo.nsectors = 1; /* セクター数 */
dinfo.buffer = dbuf; /* データ バッファ */
結果 = _bios_disk(_DISK_WRITE, &dinfo);
((結果 & 0xff00) == 0)の場合
{
fp を閉じる
gotoxy(10,14);cprintf("成功しました!!!フロッピーが5月に
今すぐ作業します。\n");
}
それ以外
{
ゴトキシ(10,14);
cprintf("ドライブ A を読み取れません。ステータス = 0x%02x\n",result);
ゴトキシ(10,16);
スイッチ(結果)
{
0x00の場合:
cprintf("\n\n ステータス:エラーなし!! ");
壊す;
ケース0x01:
cprintf("\n\n ステータス:不正なコマンド");
壊す;
ケース0x02:
cprintf("\n\n ステータス:アドレスマークが見つかりません");
壊す;
ケース0x03:
cprintf("\n\n ステータス:書き込み禁止のディスクに書き込もうとしました");
壊す;
ケース0x04:
cprintf("\n\n ステータス:セクターが見つかりません");
壊す;
ケース0x06:
cprintf("\n\n ステータス:最後の操作以降にディスクが変更されました");
壊す;
ケース0x08:
cprintf("\n\n ステータス:ダイレクト メモリ アクセス (DMA) オーバーラン");
壊す;
ケース0x09:
cprintf("\n\n ステータス: 64K 境界を越えて DMA を実行しようとしています");
壊す;
ケース 0x0C:
cprintf("\n\n ステータス:メディアタイプが見つかりません");
壊す;
ケース0x10:
cprintf("\n\n ステータス:ディスク読み取り時の CRC/ECC が不良です");
壊す;
ケース0x20:
cprintf("\n\n ステータス:コントローラーが失敗しました");
壊す;
ケース0x31:
cprintf("\n\n ステータス:ドライブにメディアがありません (IBM/MS INT 13H 拡張) ");
壊す;
ケース0x32:
cprintf("\n\n ステータス: CMOS に保存されているドライブ タイプが正しくありません (Compaq) ");
壊す;
ケース0x40:
cprintf("\n\n ステータス:シーク操作に失敗しました");
壊す;
ケース0x80:
cprintf("\n\n ステータス:添付ファイルが応答しませんでした(ディスクがタイムアウトしました) ");
壊す;
ケース0xB0:
cprintf("\n\n ステータス:ボリュームがドライブ内でロックされていません (INT 13H 拡張) ");
壊す;
ケース0xB1:
cprintf("\n\n ステータス:ドライブ内のボリュームがロックされています (INT 13H 拡張) ");
壊す;
ケース0xB2:
cprintf("\n\n ステータス:ボリュームは削除できません (INT 13H 拡張) ");
壊す;
ケース0xB3:
cprintf("\n\n ステータス:ボリュームは使用中 (INT 13H 拡張) ");
壊す;
ケース0xB4:
cprintf("\n\n ステータス:ロックカウントを超えました (INT 13H 拡張) ");
壊す;
ケース0xB5:
cprintf("\n\n ステータス:有効な排出要求が失敗しました (INT 13H 拡張) ");
壊す;
デフォルト: cprintf("\n\n ステータス:フロッピー エラーの不明ステータス コード");
}
}
0を返します。
}
プログラムコーディングに関するコメント:
前述のプログラムコーディングでは、基本的に次のタスクを段階的に実行していきます。
- dinfo は、_bios_disk 関数によって実行される操作に必要なパラメータの情報を含む diskinfo_t 構造体を指します。
- ディスクの最初のセクターに情報を書き込むので、セクターの場所は次のようになります。
- 前のプログラムによって、新しいフロッピーの 512 バイトのブート イメージ情報が保存されたファイルを開きます。ファイル名とパスは、文字配列 fname に格納されます。
- 割り込み 13H (関数 00h) を使用してディスク システムを初期化します。ここで、regs.h.ah = 0x00 は関数 00 H を指し、regs.h.dl = 0x00 はフロッピーに使用されます。また、int86(0x13, ®s, ®s) は MS-DOS 割り込みサービス INT 13 H を呼び出します。
- _bios_disk(_DISK_WRITE, &dinfo) は、指定されたファイルからのブート情報をフロッピー ディスクの最初の (指定された) セクターに書き込みます。
- 返されたステータスは結果に保存され、操作が成功した場合にメッセージを表示したり、エラーが発生した場合に画面にエラー メッセージを表示したりするために使用されます。
パラメータ |
それが意味するもの |
dinfo.ドライブ = 0x00 |
フロッピーディスクドライブであるドライブ0 ( a :)を示します。 |
dinfo.head = 0 |
ヘッド番号0を指します |
dinfo.track = 0 |
トラック0を指します |
dinfo.セクター = 1 |
フロッピーの最初のセクター、つまりセクター1 |
dinfo.セクター = 1 |
書き込み操作で考慮するセクター数 = 1 |
dinfo.バッファ = dbuf |
操作用のデータバッファ |
単一のプログラムで実行してみましょう
これで、フロッピー ディスクからのデータ回復のこのようなタイプの背後にある概念を理解していただけたと思います。次に、前に説明した 2 つのプログラムを使用して得られたのと同じ結果を提供する単一のプログラムを想像してみましょう。
私たちは最近議論したプログラムで次のタスクを実行していました。
- 正常なフロッピーディスクからブート情報をファイルに保存する
- この情報を、現在読み取り不可能なフロッピーの最初のセクターに貼り付けます。ブート イメージを保存するために使用していたファイルは、両方のプログラムの動作を接続する中間ブリッジとして機能していました。ただし、このブート情報をプログラム コーディング自体に定義すると、ファイルを作成する必要がなくなり、ファイルからフロッピーのブート情報を読み取る必要もなくなります。
次のプログラムでは、読み取り不可能なフロッピー ディスクの最初のセクターに書き込む必要がある内容をプログラムに伝えます。これにより、2 つの異なるプログラムが同じタスクを実行することを回避でき、新しい単一のプログラムから以前と同じ方法でデータを回復できます。
これにより、コーディングが少なくなり、プログラムがシンプルになり、ファイルの読み取り、書き込み、作成エラーの発生確率を減らすことができます。このプログラムでは、次の 4 つの重要なタスクを実行しています。
dbuf[512]の512バイトの16進情報を見て、プログラムの記述や理解が難しいとは思わないでください。後ほど、プログラムコーディングのためにこの情報を書き込む簡単な方法について説明します。
- 現在読み取り不可能なフロッピーの最初のセクターに書き込まれる DOS ブート レコード情報を 16 進数で定義します。
- ディスク システムをリセットしてフロッピー ディスクを初期化します (INT 13H、機能 00H)。
- DOSブートレコードをフロッピーの最初のセクターに書き込む
- 操作が正常に完了したかどうか、またエラーが発生した場合はエラーの有無を確認します。
プログラムを調べてみましょう:
/*読み取り不可能なフロッピー ディスクにデフォルトのブート イメージをロードする単一のプログラム*/
#include <bios.h>
#include <stdio.h>
int メイン(void)
{
構造体 diskinfo_t dinfo;
組合 REGS 規則:
int 結果、i;
/*フロッピーディスクドライブにロードされるブートイメージ*/
静的char dbuf[512]=
{
0xEB、0x3E、0x90、0x2B、0x29、0x6E、0x70、0x32、0x49、0x48、0x43、0x0、0x2、0x1、0x1、0x0、
0x2、0xE0、0x0、0x40、0xB、0xF0、0x9、0x0、0x12、0x0、0x2、0x0、0x0、0x0、0x0、0x0、0x0、
0x0、0x0、0x0、0x0、0x29、0x24、0x3B、0xDB、0x16、0x4E、0x4F、0x20、0x4E、0x41、0x4D、0x45、
0x20、0x20、0x20、0x20、0x46、0x41、0x54、0x31、0x32、0x20、0x20、0x20、0xF1、0x7D、0xFA、
0x33、0xC9、0x8E、0xD1、0xBC、0xFC、0x7B、0x16、0x7、0xBD、0x78、0x0、0xC5、0x76、0x0、
0x1E、0x56、0x16、0x55、0xBF、0x22、0x5、0x89、0x7E、0x0、0x89、0x4E、0x2、0xB1、0xB、0xFC、
0xF3、0xA4、0x6、0x1F、0xBD、0x0、0x7C、0xC6、0x45、0xFE、0xF、0x8B、0x46、0x18、0x88、0x45、
0xF9、0xFB、0x38、0x66、0x24、0x7C、0x4、0xCD、0x13、0x72、0x3C、0x8A、
0x46,0x10,0x98,0xF7,
0x66,0x16,0x3, 0x46,0x1C,0x13,0x56, 0x1E,0x3,0x46,0xE,0x13,
0xD1,0x50,0x52,0x89,
0x46,0xFC,0x89, 0x56,0xFE,0xB8,0x20,0x0, 0x8B,0x76,0x11,0xF7,
0xE6,0x8B,0x5E,0xB、
0x3、0xC3、0x48、0xF7、0xF3、0x1、0x46、0xFC、0x11、0x4E、0xFE、0x5A、
0x58,0xBB,0x0,0x7,
0x8B、0xFB、0xB1、0x1、0xE8、0x94、0x0、0x72、0x47、0x38、0x2D、0x74、0x19、0xB1、0xB、0x56、
0x8B、0x76、0x3E、0xF3、0xA6、0x5E、0x74、0x4A、0x4E、0x74、0xB、0x3、0xF9、0x83、0xC7、0x15、
0x3B、0xFB、0x72、0xE5、0xEB、0xD7、0x2B、0xC9、0xB8、0xD8、0x7D、0x87、0x46、0x3E、0x3C、
0xD8,0x75,0x99, 0xBE,0x80,0x7D,0xAC, 0x98,0x3,0xF0,0xAC,0x84,0xC0,0x74,0x17,0x3C,
0xFF、0x74、0x9、0xB4、0xE、0xBB、0x7、0x0、0xCD、0x10、0xEB、0xEE、0xBE、0x83、0x7D、0xEB、
0xE5、0xBE、0x81、0x7D、0xEB、0xE0、0x33、0xC0、0xCD、0x16、0x5E、0x1F、0x8F、0x4、0x8F、0x44、
0x2,0xCD、0x19、0xBE、0x82、0x7D、0x8B、0x7D、0xF、0x83、0xFF、0x2、0x72、0xC8、0x8B、0xC7、0x48、
0x48,0x8A,0x4E,0xD,0xF7,0xE1,0x3,0x46,0xFC, 0x13,0x56,0xFE,0xBB,0x0,0x7,0x53,0xB1,0x4,
0xE8,0x16,0x0, 0x5B,0x72,0xC8, 0x81,0x3F,0x4D,0x5A, 0x75,0xA7,0x81,0xBF, 0x0,0x2,0x42,0x4A,
0x75,0x9F,0xEA,0x0,0x2,0x70,0x0,0x50,0x52,0x51,0x91,0x92,0x33,0xD2,0xF7,0x76,0x18,0x91,
0xF7、0x76、0x18、0x42、0x87、0xCA、0xF7、0x76、0x1A、0x8A、0xF2、0x8A、0x56、0x24、0x8A、0xE8、
0xD0、0xCC、0xD0、0xCC、0xA、0xCC、0xB8、0x1、0x2、0xCD、0x13、0x59、0x5A、0x58、0x72、0x9、0x40、
0x75,0x1,0x42,0x3, 0x5E,0xB,0xE2,0xCC,0xC3,0x3,0x18,0x1,0x27,0xD,0xA,0x49, 0x6E,
0x76,0x61,0x6C,0x69,0x64,0x20, 0x73, 0x79, 0x73, 0x74, 0x65,0x6D,0x20,0x64,0x69,0x73,
0x6B、0xFF、0xD、0xA、0x44、0x69、0x73、0x6B、0x20、0x49、0x2F、0x4F、0x20、0x65、0x72、0x72、0x6F、
0x72,0xFF,0xD,0xA,0x52, 0x65,0x70,0x6C,0x61,0x63, 0x65,0x20,
0x74,0x68,0x65,0x20,
0x64、0x69、0x73、0x6B、0x2C、0x20、0x61、0x6E、0x64、0x20、0x74、0x68、0x65、0x6E、0x20、0x70、
0x72,0x65, 0x73,0x73, 0x20,0x61, 0x6E,0x79,0x20,0x6B,0x65,0x79,0xD,0xA, 0x0,0x49,0x4F,
0x20,0x20,0x20,0x20, 0x20,0x20, 0x20,0x20,0x53,0x59,0x53,0x4D, 0x53, 0x44, 0x4F, 0x53,0x20,0x20,
0x20,0x53, 0x59,0x53, 0x80,0x1,0x0,0x57,0x49, 0x4E,0x42, 0x4F,0x4F,0x54,0x20,0x53, 0x59
,0x53,0x0,0x0,0x55,0xAA};
clrscr();
dinfo.drive = 0x00; /* A のドライブ番号: */
dinfo.head = 0; /* ディスクヘッド番号 */
dinfo.track = 0; /* トラック番号 */
dinfo.sector = 1; /* セクター番号 */
dinfo.nsectors = 1; /* セクター数 */
dinfo.buffer = dbuf; /* データ バッファ */
ゴトキシ(10,9);
cprintf("フロッピーディスクドライブから読み取ろうとしています:\n");
///ディスクシステムを初期化します\\\
(i=0; i<3; i++) の場合
{
regs.h.ah = 0x00; /* ディスクシステムをリセット */
regs.h.dl = 0x00; /* フロッピーディスク a: */
int86(0x13, ®s, ®s);
}
結果 = _bios_disk(_DISK_WRITE, &dinfo);
((結果 & 0xff00) == 0)の場合
{
ゴトキシ(10,14);
cprintf("ディスク書き込みステータス:成功。\n");
}
それ以外
{
ゴトキシ(10,14);
cprintf("ドライブ A を読み取れません、ステータス = 0x%02x\n",
結果);
ゴトキシ(10,16);
スイッチ(結果)
{
0x00の場合:
cprintf("\n\n ステータス:エラーなし!! ");
壊す;
ケース0x01:
cprintf("\n\n ステータス:不正なコマンド");
壊す;
ケース0x02:
cprintf("\n\n ステータス:アドレスマークが見つかりません");
壊す;
ケース0x03:
cprintf("\n\n ステータス:書き込みを試みています-
保護されたディスク");
壊す;
ケース0x04:
cprintf("\n\n ステータス:セクターが見つかりません");
壊す;
ケース0x06:
cprintf("\n\n ステータス:最後の操作以降にディスクが変更されました");
壊す;
ケース0x08:
cprintf("\n\n ステータス:ダイレクト メモリ アクセス (DMA) オーバーラン");
壊す;
ケース0x09:
cprintf("\n\n ステータス: 64K 境界を越えて DMA を実行しようとしています");
壊す;
ケース 0x0C:
cprintf("\n\n ステータス:メディアタイプが見つかりません");
壊す;
ケース0x10:
cprintf("\n\n ステータス:ディスク読み取り時の CRC/ECC が不良です");
壊す;
ケース0x20:
cprintf("\n\n ステータス:コントローラーが失敗しました");
壊す;
ケース0x31:
cprintf("\n\n ステータス:ドライブにメディアがありません (IBM/MS INT 13H 拡張) ");
壊す;
ケース0x32:
cprintf("\n\n ステータス: CMOS に保存されているドライブ タイプが正しくありません (Compaq) ");
壊す;
ケース0x40:
cprintf("\n\n ステータス:シーク操作に失敗しました");
壊す;
ケース0x80:
cprintf("\n\n ステータス:添付ファイルが応答しませんでした(ディスクがタイムアウトしました) ");
壊す;
ケース0xB0:
cprintf("\n\n ステータス:ボリュームがドライブ内でロックされていません (INT 13H 拡張) ");
壊す;
ケース0xB1:
cprintf("\n\n ステータス:ドライブ内のボリュームがロックされています (INT 13H 拡張) ");
壊す;
ケース0xB2:
cprintf("\n\n ステータス:ボリュームは削除できません (INT 13H 拡張) ");
壊す;
ケース0xB3:
cprintf("\n\n ステータス:ボリュームは使用中 (INT 13 拡張) ");
壊す;
ケース0xB4:
cprintf("\n\n ステータス:ロックカウントを超えました (INT 13H 拡張) ");
壊す;
ケース0xB5:
cprintf("\n\n ステータス:有効な排出要求が失敗しました (INT 13H 拡張) ");
壊す;
デフォルト: cprintf("\n\n ステータス:フロッピー エラーの不明ステータス コード");
}
}
0を返します。
}
このプログラムコーディングでは、基本的に次のタスクを段階的に実行していきます。
- 静的文字データ バッファ dbuf[512] には、読み取り不可能なフロッピーの最初のセクターに書き込まれる 16 進数で 512 バイトの情報が提供されます。dbuf[512] は、操作中にコンピュータにフロッピーの最初のセクターに書き込まれる情報を通知します。(次のプログラムを参照)
- dinfo は、_bios_disk 関数によって実行される操作に必要なパラメータの情報を含む diskinfo_t 構造体を指します。
- ディスクの最初のセクターに情報を書き込むので、セクターの場所は次のようになります。
パラメータ |
それが意味するもの |
dinfo.ドライブ = 0x00 |
フロッピーディスクドライブであるドライブ0 ( a :)を示します。 |
dinfo.head = 0 |
ヘッド番号0を指します |
dinfo.track = 0 |
トラック0を指します |
dinfo.セクター = 1 |
フロッピーの最初のセクター、つまりセクター1 |
dinfo.セクター = 1 |
書き込み操作で考慮するセクター数 = 1 |
dinfo.バッファ = dbuf |
操作用のデータバッファ |
- 割り込み 13H (関数 00h) を使用してディスク システムを初期化します。ここで、regs.h.ah = 0x00 は関数 00 H を指し、regs.h.dl = 0x00 はフロッピーに使用されます。また、int86(0x13, ®s, ®s) は MS-DOS 割り込みサービス INT 13 H を呼び出します。
- _bios_disk(_DISK_WRITE, &dinfo) は、指定されたファイルからのブート情報をフロッピー ディスクの最初の (指定された) セクターに書き込みます。
返されたステータスは結果に保存され、操作が成功した場合にメッセージを表示したり、エラーが発生した場合に画面にエラー メッセージを表示したりするために使用されます。
以前のプログラムで使用するためにブートイメージを16進文字で保存する
先ほど説明したプログラムで、フロッピーの DOS ブート レコードの 512 文字すべてを 16 進数でエラーなしで手動で書き込むのは、非常に難しい作業です。正確に書き込むことができたとしても、これは困難で時間のかかる作業です。データ バッファー dbuf[512] のデータをファイルに保存するには、ちょっとしたコツが必要です。
Cプログラミングでは16進文字は0xで表され、16進文字がA9 Hの場合、Cプログラムでは0xA9と書きます。次のプログラムも同じことを行います。前のプログラムで書き込む必要のあるデータを、データバッファdbuf[512]のデータとして保存します。
必要なのは、新しいフロッピー ディスクを使用して DBR のイメージを作成し、指定された宛先ファイルからこのプログラムの出力をコピーして、このデータをプログラムに貼り付けるだけです。必要に応じてフォーマットしてください。どのように機能するか見てみましょう。
/*フロッピーディスクのブートイメージを 16 進文字で作成するプログラム*/
#include <bios.h>
#include <stdio.h>
int メイン(void)
{
構造体 diskinfo_t dinfo;
ユニオン REGS regs;
int 結果、i;
整数カウント=0;
char fname[80];
静的char dbuf[512];
ファイル *fp;
dinfo.drive = 0x00; /* A のドライブ番号: */
dinfo.head = 0; /* ディスクヘッド番号 */
dinfo.track = 0; /* トラック番号 */
dinfo.sector = 1; /* セクター番号 */
dinfo.nsectors = 1; /* セクター数 */
dinfo.buffer = dbuf; /* データ バッファ */
clrscr();
gotoxy(10,3);cprintf("ファイル名とパスを入力してください
ブートイメージを HEX システムに保存します");
ゴトキシ(5,5);
取得(fname);
fp = fopen(fname、"wb");
if((fp=fopen(fname,"wb"))==NULL)
{
ハイビデオ();
gotoxy(10,10);cprintf("ファイルを作成できませんでした");
getch();
終了(0);
}
///ディスクシステムを初期化します\\\
(i=0; i<3; i++) の場合
{
regs.h.ah = 0x00; /* ディスクシステムをリセット */
regs.h.dl = 0x00; /* フロッピーディスク a: */
int86(0x13, ®s, ®s);
}
gotoxy(10,9); cprintf("フロッピーから読み取ろうとしています
ディスクドライブ:\n");
結果 = _bios_disk(_DISK_READ, &dinfo);
((結果 & 0xff00) == 0)の場合
{
ゴトキシ(10,14);
cprintf("フロッピーディスクドライブからディスクを読み取りました:
成功しました。\n");
while(カウント<512)
{
fprintf(fp,"0x%X, ",dbuf[count] & 0xff);
カウント++;
}
fp を閉じる
}
それ以外
{
ゴトキシ(10,14);
cprintf("ドライブ A を読み取れません、ステータス = 0x%02x\n",
結果);
}
0を返します。
}
プログラムのコーディングに関するコメント:
データは指定されたファイルに保存されます。データをプログラムにコピーし、必要なフォーマットを行うだけです。手順全体を通して、次のヒントを忘れないでください。
- プログラムの操作が成功し、宛先ファイルに保存されたデータが適切であることを確認します。
- 予想されるエラーが発生していないか、操作全体をチェックする必要があります。
- ブート セクターを読み取る前に、プログラムを使用してフロッピー ディスクを初期化する必要があります。この目的には、INT 13H の機能 00H を使用できます。
方法 – 2
方法 1 が機能しない場合はどうすればよいですか?
方法 1 が機能せず、読み取り不可能なディスクによってプログラムが最初のセクターのブート情報を書き換えることができない場合は、この 2 番目の方法を試してください。最初の方法が失敗する理由は、フロッピー ディスクの最初のセクターの物理的な破損である可能性があります。
この 2 番目の方法では、読み取り不能なフロッピーの表面のすべてのデータを 1 つのファイルに一時的にコピーし、このイメージを別の正常なディスクの表面に直接貼り付けます。
この手順には、次の 2 つの重要なステップが含まれます。
- セクタ単位でフロッピー メディアの表面のすべてのデータを 1 つのファイルに一時的にコピーします。
- 以前にファイルに保存したデータを、そのまま新しいフロッピーの同じセクターに貼り付けます。
メディアサーフェスのすべてのデータを1つのファイルにコピーします
フロッピー メディアの表面のすべてのデータを保存するには、プログラムは次の 3 つのタスクを実行する必要があります。
- INT 13H の機能 00H を使用してディスクを適切に初期化します。
- 表面のセクターごとの情報を読み取り、単一のファイルに保存します。
- 読み取り操作が成功したかどうかを確認する(最も重要)
フロッピー ディスクの初期化に問題が発生することは非常に一般的であり、多くの読み取り失敗メッセージにつながります。そのため、読み取り書き込み操作の前に、プログラミングを使用してディスクを初期化する必要があります。
フロッピーに対して何らかの操作を行った場合、その操作が成功したかどうかを確認することが最も重要かつ必要な手順です。
初期化後でも、最近挿入したフロッピー ディスクまたは交換したフロッピー ディスクで読み取りエラーが発生する場合は、プログラムを再度実行することをお勧めします。おそらく今回は機能するでしょう。
次のプログラムは、これらの指定されたタスクを実行します。どのように進行するかを見てみましょう。
/*フロッピーディスクの物理面のデータをファイルに保存するプログラム*/
#include <bios.h>
#include <stdio.h>
void main(void)
{
int ヘッド、トラック;
ユニオン REGS regs;
int 結果、i、セクター;
char ファイル名[80];
構造体 diskinfo_t dinfo;
静的char dbuf[512];
ファイル *tt;
clrscr();
printf("\n 保存するファイル名とパスを入力してください
一時的にデータ\n");
ファイル名を取得します。
if((tt=fopen(ファイル名,"wb"))==NULL)
{
printf("ファイルを作成できませんでした、
終了するには任意のキーを押してください");
getch();
終了(0);
}
printf("\n フロッピーディスクシステムを初期化しています...\n");
///ディスクシステムを初期化します\\\
(i=0; i<3; i++) の場合
{
regs.h.ah = 0x00; /* ディスクシステムをリセット */
regs.h.dl = 0x00; /* フロッピーディスク a: */
int86(0x13, ®s, ®s);
}
(トラック=0;トラック<=79;トラック++)
{
(ヘッド=0;ヘッド<=1;ヘッド++)
{
for(セクター=1;セクター<=18;セクター++)
{
dinfo.drive = 0; /* A のドライブ番号: */
dinfo.head = head; /* ディスクヘッド番号 */
dinfo.track = track; /* トラック番号 */
dinfo.sector = sector; /* セクター番号 */
dinfo.nsectors = 1; /* セクター数 */
dinfo.buffer = dbuf; /* データ バッファ */
結果 = _bios_disk(_DISK_READ, &dinfo);
((結果 & 0xff00) == 0)の場合
{
(i=0;i<512;i++) の場合
fprintf(tt,"%c",dbuf[i] & 0xff);
}
それ以外
{
printf("ドライブAを読み取れません、ステータス =
0x%02x\t%d\t%d\t%d\n", 結果、ヘッド、トラック、セクター);
}
printf("読み取りトラック= %d ヘッド= %d セクター= %d\n",
トラック、ヘッド、セクター);
}
}
}
}
プログラムコーディングに関するコメント:
前述のプログラムコーディングでは、基本的に次のタスクを段階的に実行していきます。
- 文字配列filename[80]には、データを一時的に保存するファイルのユーザー定義パスとファイル名が格納されます。
- dinfo は、_bios_disk 関数によって実行される操作に必要なパラメータの情報を含む diskinfo_t 構造体を指します。
- 割り込み 13H (関数 00h) を使用してディスク システムを初期化します。ここで、regs.h.ah = 0x00 は関数 00 H を指し、regs.h.dl = 0x00 はフロッピーに使用されます。また、int86(0x13, ®s, ®s) は MS-DOS 割り込みサービス INT 13 H を呼び出します。
- ディスクの表面のすべての情報を読み取るため、_bios_disk のパラメータは次のようになります。
パラメータ |
それが意味するもの |
dinfo.ドライブ = 0x00 |
フロッピーディスクドライブであるドライブ0 ( a :)を示します。 |
dinfo.head =ヘッド |
フロッピーには2つの面(2つのヘッド)があるため、ヘッド番号0と1を指します。 |
dinfo.track =トラック |
フロッピーの各面には80 個のトラックがあるため、トラック0 から 79 を指します。 |
dinfo.sector =セクター |
各トラックには18 個のセクターがあるため、セクター1 から 18 を指します。 |
dinfo.セクター = 1 |
読み取り操作で考慮するセクター数 = 1 |
dinfo.バッファ = dbuf |
操作用のデータバッファ |
- _bios_disk(_DISK_READ, &dinfo) は、dinfo で指定されたセクターからフロッピー ディスクの物理表面からデータを読み取ります。
- 返されたステータスは結果に保存され、操作が成功した場合にメッセージを表示したり、エラーが発生した場合に画面にエラー メッセージを表示したりするために使用されます。
フロッピーディスクのデータのイメージを保持するファイルのサイズは、正確に1,474,560バイトでなければならないことを常に覚えておいてください。フロッピーには80のトラック(0から79)、2つの面またはヘッド(ヘッド0とヘッド1)があり、各トラックには18のセクターがあり、各セクターには512バイトのデータが格納されます。
合計バイト数 = (トラック数) * (ヘッド数) *
(トラックあたりのセクター数) * 512
= 80*2*18*512
= 1,474,560 バイト
したがって、フロッピー ディスクの任意のセクターの読み取りでエラーが発生すると、ファイルのサイズが 1,474,560 バイトから変更され、このファイルからセクターごとにディスク イメージを書き込む宛先ディスクでは、情報全体が完全にまたは部分的に役に立たなくなります。
これは、コンピュータがフロッピー ディスクのメディアの表面にあるファイルの情報を、割り当て単位に割り当てられたセクター範囲内で読み取るためです。ファイルのデータのセクターが変更されると、ファイル情報全体が変更されます。
セクター読み取りエラーの解決方法を考える
不良または読み取り不能なフロッピーの場合、ディスクの表面の領域が不良で、ディスクの表面から情報を読み取ることができない可能性があります。
この状態では、このセクターの情報はスキップされ、この場合のイメージ ファイルのサイズが 1,474,560 バイトと異なるため、フロッピーのイメージは他のセクターに対しても歪んでしまいます。
イメージ ファイルのサイズを維持し、残りの情報を宛先ディスクの正確なセクター位置に貼り付けるために、512 バイトの元のデータの代わりに他の情報を書き込みます。この方法では、残りの情報を保存できますが、この場合の回復は部分的な回復になる可能性があります。
システムがソースフロッピーの最初のセクターの読み取りにも失敗する場合は、イメージを宛先フロッピーに貼り付けた後、前述のプログラムを実行して、フロッピーのDOS ブート レコードを書き換える必要があります。
プログラミングでどのように実現できるか見てみましょう。
#include <bios.h>
#include <stdio.h>
void main(void)
{
int ヘッド、トラック;
ユニオン REGS regs;
int 結果、i、セクター;
char ファイル名[80];
構造体 diskinfo_t dinfo;
静的char dbuf[512];
/*不良セクタのスペースを埋めるための 512 バイトの情報*/
/// 512 バイトのスペースを埋めるために 512 個のゼロを使用しました\\\
静的char dbuf2[512] =
"0000000000000000000000000000000" "0000000000000000000000000000000" "00000000000000000000000000000000" "0000000000000000000000000000000" "0000000000000000000000000000000" "00000000000000000000000000000000" "000000000000000000000000000000" "0000000000000000000000000000000" "0000000000000000000000000000000" "00000000000000000000000000000000" "0000000000000000000000000000000" "0000000000000000000000000000000" "00000000000000000000000000000000" "000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000";
ファイル *tt;
clrscr();
printf("\n 保存するファイル名とパスを入力してください
一時的にデータ\n");
ファイル名を取得します。
if((tt=fopen(ファイル名,"wb"))==NULL)
{
printf("ファイルを作成できませんでした。任意のキーを押してください
出口");
getch();
終了(0);
}
printf("\n フロッピーディスクシステムを初期化しています...\n");
///ディスクシステムを初期化します\\\
(i=0; i<3; i++) の場合
{
regs.h.ah = 0x00; /* ディスクシステムをリセット */
regs.h.dl = 0x00; /* フロッピーディスク a: */
int86(0x13, ®s, ®s);
}
(トラック=0;トラック<=79;トラック++)
{
(ヘッド=0;ヘッド<=1;ヘッド++)
{
for(セクター=1;セクター<=18;セクター++)
{
dinfo.drive = 0; /* A のドライブ番号: */
dinfo.head = head; /* ディスクヘッド番号 */
dinfo.track = track; /* トラック番号 */
dinfo.sector = sector; /* セクター番号 */
dinfo.nsectors = 1; /* セクター数 */
dinfo.buffer = dbuf; /* データ バッファ */
結果 = _bios_disk(_DISK_READ, &dinfo);
((結果 & 0xff00) == 0)の場合
{
(i=0;i<512;i++) の場合
fprintf(tt,"%c",dbuf[i] & 0xff);
}
それ以外
{
printf("ドライブAを読み取れません、ステータス =
0x%02x\t%d\t%d\t%d\n", 結果、ヘッド、トラック、セクター);
/*セクターが読み取り可能でない場合は、dbuf2 で 512 バイトを占有します*/
fwrite(dbuf2,512,1,tt);
}
printf("読み取りトラック= %d ヘッド= %d セクター= %d\n",
トラック、ヘッド、セクター);
}
}
}
}
プログラムコーディングに関するコメント:
プログラムのコーディングでは、データ バッファー dbuf2[512] を除いて、すべてのステップは前のプログラムと同じです。データ バッファー dbuf2[512] は、ディスク読み取り操作中に不良セクタによって生成されたエラーを処理し、イメージ ファイルのサイズを維持するために使用します。
こうすることで、不良セクタから読み取れなかった情報のスペースを埋め、ディスク イメージの正確性を維持するために 512 バイトの疑似情報を書き込むことになります。
ファイルから新しいフロッピーの物理的な表面にデータを貼り付けます。
この手順では、前のプログラムによってファイルに保存されたデータを、ファイルにコピーしたのと同じ方法で、セクターごとに新しいフロッピーの物理表面に貼り付けます。
プログラムは主に以下のステップで進行します。
- 読み取り不能なフロッピーの表面データを一時的に保存したファイルを開きます。
- INT 13H のリセット機能 00H によってディスク システムを適切に初期化します。
- ファイルから新しいフロッピーのセクターに関する情報を書き込みます。
- 書き込みステータスを同時に表示して、エラーの発生を発見または回避します。
プログラムのソースコードは以下に記載されています。どのように動作するかを見てみましょう。
/*前のプログラムで作成されたファイルから新しいフロッピーの表面のセクターにデータを書き込むプログラム*/
#include <bios.h>
#include <stdio.h>
void main(void)
{
int ヘッド、トラック;
ユニオン REGS regs;
int 結果、i、セクター;
整数カウント =0;
char ファイル名[80];
構造体 diskinfo_t dinfo;
静的char dbuf[512];
ファイル *fp;
clrscr();
printf("\n 保存するファイル名とパスを入力してください
一時的にデータ\n");
ファイル名を取得します。
if((fp=fopen(ファイル名,"rb"))==NULL)
{
printf("ファイルを作成できませんでした。任意のキーを押してください
出口");
getch();
終了(1);
}
///ディスクシステムを初期化します\\\
(i=0; i<3; i++) の場合
{
regs.h.ah = 0x00; /* ディスクシステムをリセット */
regs.h.dl = 0x00; /* フロッピーディスク a: */
int86(0x13, ®s, ®s);
}
(トラック=0;トラック<=79;トラック++)
{
(ヘッド=0;ヘッド<=1;ヘッド++)
{
for(セクター=1;セクター<=18;セクター++)
{
カウント =0;
while(count<512 )
{
fscanf(fp,"%c",&dbuf[count]);
カウント++;
}
dinfo.drive = 0x00; /* A のドライブ番号: */
dinfo.head = head; /* ディスクヘッド番号 */
dinfo.track = track; /* トラック番号 */
dinfo.sector = sector;/* セクター番号 */
dinfo.nsectors = 1; /* セクター数 */
dinfo.buffer = dbuf; /* データ バッファ */
結果 = _bios_disk(_DISK_WRITE, &dinfo);
((結果 & 0xff00) == 0)の場合
printf("トラック = %d、ヘッド = %d への書き込みに成功しました。
セクター = %d\n", トラック、ヘッド、セクター);
それ以外
printf("ドライブ A を読み取れません、ステータス = 0x%02x\n",
結果);
}
}
}
}
プログラムコーディングに関するコメント:
前述のプログラムコーディングでは、基本的に次のタスクを段階的に実行していきます。
- 文字配列filename[80]には、読み取り不能なフロッピーの表面のデータを一時的に保存したファイルのパスとファイル名が格納されている。
- dinfo は、_bios_disk 関数によって実行される操作に必要なパラメータの情報を含む diskinfo_t 構造体を指します。
- 割り込み 13H (関数 00h) を使用してディスク システムを初期化します。ここで、regs.h.ah = 0x00 は関数 00 H を指し、regs.h.dl = 0x00 はフロッピーに使用されます。また、int86(0x13, ®s, ®s) は MS-DOS 割り込みサービス INT 13 H を呼び出します。
- ディスク表面のセクターに直接情報を書き込むため、 _bios_diskのパラメータは次のようになります。
パラメータ |
それが意味するもの |
dinfo.ドライブ = 0x00 |
フロッピーディスクドライブであるドライブ0 ( a :)を示します。 |
dinfo.head =ヘッド |
フロッピーには2つの面(2つのヘッド)があるため、ヘッド番号0と1を指します。 |
dinfo.track =トラック |
フロッピーの各面には80 個のトラックがあるため、トラック0 から 79 を指します。 |
dinfo.sector =セクター |
各トラックには18 個のセクターがあるため、セクター1 から 18 を指します。 |
dinfo.セクター = 1 |
書き込み操作で考慮するセクター数 = 1 |
dinfo.バッファ = dbuf |
操作用のデータバッファ |
- _bios_disk(_DISK_WRITE, &dinfo) は、 dinfo で指定されたフロッピー ディスクの物理表面のセクターにデータを書き込みます。
- 返されたステータスは結果に保存され、操作が成功した場合にメッセージを表示したり、エラーが発生した場合に画面にエラー メッセージを表示したりするために使用されます。
方法 2 を実行しても新しいフロッピーが動作しない場合は、方法 2 の実行中に宛先ディスクとして使用した新しいフロッピーに、さらに方法 1 を適用することができます。
これだけでなく、ディスクの破損状況に応じてヒット数や試行回数も変わる可能性があります。しかし、満足のいく結果が得られなくても心配する必要はありません。
ファイルごとに回復を試したり、次に説明するその他の多くのヒントを試したりすることができます。ここでは、ルート ディレクトリからファイル情報を収集するというアイデアを、データを回復するためのプログラミングに実装します。
削除または失われたデータの論理的回復の検討:
この章で説明したこれまでの回復ケースはすべて、DBR のみが破損し、FAT1、FAT2、およびルート ディレクトリを含むトラック 0 のセクターが読み取り可能であると予想される場合にデータを回復するためのものでした。
しかし、問題が FAT の破損によるものである場合、データがディスクから削除されている場合、またはルート ディレクトリから情報を読み取ってデータを直接回復したい場合は、ファイル名、開始クラスター、ファイルのサイズ、属性などの情報をルート ディレクトリ エントリから読み取る必要があります。
前の章でルート ディレクトリについてすでに説明したように、各ファイルまたはディレクトリには 32 バイトの情報があります。これらの 32 バイトは次のように分割されます。
バイト数 |
情報の説明 |
8 バイト |
ファイル名 |
3 バイト |
拡大 |
1 バイト |
属性 |
10 バイト |
予約済み |
2 バイト |
作成日時または最終更新日時 |
2 バイト |
作成日または最終更新日 |
2 バイト |
クラスターの開始 |
4 バイト |
ファイルサイズ |
ルート ディレクトリからファイルの情報を読み取り、そのファイルを宛先パスに統合してファイルを回復することで、データを回復します。次のプログラムは、次の手順を実行してデータを回復します。
- ルート ディレクトリ エントリを読み取り、ファイル/ディレクトリ名、ファイルの拡張子、ファイルの開始クラスター サイズ (バイト単位) などのすべての情報とともに画面に表示します。
- サブディレクトリ内のファイルとディレクトリの情報を読み取り、必要に応じて表示します。
- 復元するファイル名を確認し、復元を続行します。
- 回復する指定されたファイルのCHS (シリンダー、ヘッド、セクター) 情報を計算します。
- ディスクのデータ領域からファイルのデータを統合し、復元したファイルを指定されたパスの指定された宛先ファイル名に保存します。
このプログラムは、フロッピーのブート情報が読み取り可能かどうかは気にしません。したがって、破損したフロッピー ディスクから削除されたデータも回復できます。プログラムのコーディングを見てみましょう。
/*ルートディレクトリからファイル情報を読み取ってフロッピーディスクからデータを回復するプログラム*/
#include<stdio.h>
#include<bios.h>
#include<dos.h>
void main()
{
void Display_Information(符号なし整数、符号なし整数、
符号なし整数);
符号なし整数 トラック=0、ヘッド=1、セクター=2;
Display_Information(トラック、ヘッド、セクター);
} /*メイン終了 */
void Display_Information(符号なし整数トラック、
符号なし整数ヘッド、
符号なし整数セクター)
{
void を回復します(unsigned int *、unsigned int);
char buf[512]; // 512バイトのバッファ
文字 ch;
struct diskinfo_t finfo; //構造体、_bios_disk によって使用される
unsigned int result,i,j, count=0; /* 符号なし整数
定義済み */
unsigned int file_no; /* 符号なし整数
ファイル番号 */
構造体
{
unsigned int name[8],ext[3]; /* 8.3のDOSのファイル名
(8ドット3) 形式 */
unsigned int attribute; // ファイル/ディレクトリ属性
unsigned int start; // ファイルの開始クラスター
long unsigned int size; // ファイルのサイズ(バイト単位)
}root[32]; /* 32バイトの情報
ルート内のファイル/ディレクトリ
ディレクトリ */
clrscr();
する
{
ファイル番号=0;
finfo.drive = 0x00; /* A のドライブ番号: */
finfo.head = head; /* ディスクヘッド番号 */
finfo.track = track; /* トラック番号 */
finfo.sector= sector; /* セクター番号 */
finfo.nsectors=1; /* セクター数 */
finfo.buffer = buf; /* データバッファ */
result = _bios_disk(_DISK_READ, &finfo); /* 読み取り
セクター */
if( (result & 0xff00) != 0) /* 読み取りエラーの場合は表示
エラーメッセージと終了*/
{
printf("読み取りエラー");
getch();
exit(0); // DOSに戻る
}
///情報表示画面フォーマット\\\
clrscr();
ゴトキシ(9,1);
cprintf("表示シリンダー: %u、ヘッド: %u、セクター: %u",
トラック、ヘッド、セクター);
ゴトキシ(9,2);
cprintf("FNO NAME EXT ATTRIBUTE START SIZE");
ゴトキシ(7,3);
cprintf("-------------------------------------");
/*一度に 1 つのセクター。各ファイル/DIR エントリは 32 バイトを消費します*/
(i=0;i<512;i+=32) の場合
{
(j=0;j<8;j++) の場合
{
///ファイル/ディレクトリ名を検索\\\
root[file_no].name[j]=buf[j+i];
}
(j=8;j<11;j++) の場合
{
///拡張子を見つける\\\
root[ファイル番号].ext[j-8]=buf[i+j];
}
11 ;
root[file_no].attribute=buf[i+j]; /// 属性
///クラスターを起動しています\\\
root[file_no].start=(0xff & buf[27+i])*16*16 + (0xff & buf[26+i]);
///サイズを計算する\\\
root[file_no].size =(long unsigned int)(0xff &
バッファ[31+i])*16*16*16*16*16*16*16*16;
root[file_no].size+=(long unsigned int)(0xff &
バッファ[30+i])*16*16*16*16;
root[file_no].size+=(long unsigned int)(0xff &
バッファ[29+i])*16*16;
root[file_no].size+=(long unsigned int)(0xff &
バッファ[28+i]);
if((root[file_no].start == 0) ||
(ルート[ファイル番号].属性 == 15))
続く;
それ以外
{
ゴトキシ(8,i/32+4);
cprintf("%2u",file_no); /* ファイルを表示
番号 */
(j=0;j<8;j++) の場合
{
ゴトキシ(14+j,i/32+4);
cprintf("%c",root[file_no].name[j]); /* ファイルを表示
名前 */
}
(j=0;j<3;j++) の場合
{
ゴトキシ(26+j,i/32+4);
cprintf("%c",root[file_no].ext[j]); /* 表示
拡大 */
}
ゴトキシ(30,i/32+4);
cprintf("%u",root[file_no].attribute); /* 表示
属性 */
if(ルート[ファイル番号].属性==16)
{
ゴトキシ(33,i/32+4);
cprintf("<DIR>"); /* ディレクトリ属性がある場合に表示 */
}
それ以外
{
ゴトキシ(33,i/32+4);
cprintf("<FILE>"); /* エントリはファイルです */
}
ゴトキシ(44,i/32+4);
cprintf("%-5u", root[file_no].start); /* 表示
クラスターを起動しています */
ゴトキシ(58,i/32+4);
cprintf("%-10lu", root[file_no].size); /* ファイルのサイズ
ファイル */
}
ファイル番号++;
}
ゴトキシ(10,
cprintf("「M」を押してください: 他のファイルのリストを見るには&quo
ゴトキシ(10,
cprintf("「R」を押す:上記からファイルを回復するには
リスト
ch=getc
s (E5H) で始まるファイル名は、ファイルが削除され、ファイル名の最初の文字が s に置き換えられたことを表していることに注意してください (前の章のルート ディレクトリの説明を参照してください)。
プログラムの出力は次のように表示されます。
表示シリンダ: 0、ヘッド: 1、セクター: 2
FNO 名前 外部属性 開始サイズ
--------------------------------------------------------------------------
0 WE 32 <ファイル> 15 1800
1 s2_INFO C 32 <ファイル> 5 4700
2 THELP CFG 32 <ファイル> 2 22
3 THELP COM 32 <ファイル> 3 11072
4 TIMEIT CPP 32 <ファイル> 39 1186
5 TOUCH COM 32 <ファイル> 42 5124
6 TRY1 CPP 32 <ファイル> 53 1581
7 TURBOC CFG 32 <ファイル> 57 30
8 AA CPP 32 <ファイル> 58 260
9 ABC CPP 32 <ファイル> 59 1036
10 ASSIGN1 CPP 32 <ファイル> 62 4257
11 CH24_2 CPP 32 <ファイル> 71 834
12 sBSDISK1 C 32 <ファイル> 73 911
13 sH24_25 C 32 <ファイル> 75 594
14 sBSDISK C 32 <ファイル> 77 840
「M」を押す:さらにファイルのリストを見るには
「R」を押す:上記のリストからファイルを回復するには R
|
表示シリンダ: 0、ヘッド: 1、セクター: 2
FNO 名前 外部属性 開始サイズ
--------------------------------------------------------------------------
0 WE 32 <ファイル> 15 1800
1 s2_INFO C 32 <ファイル> 5 4700
2 THELP CFG 32 <ファイル> 2 22
3 THELP COM 32 <ファイル> 3 11072
4 TIMEIT CPP 32 <ファイル> 39 1186
5 TOUCH COM 32 <ファイル> 42 5124
6 TRY1 CPP 32 <ファイル> 53 1581
7 TURBOC CFG 32 <ファイル> 57 30
8 AA CPP 32 <ファイル> 58 260
9 ABC CPP 32 <ファイル> 59 1036
10 ASSIGN1 CPP 32 <ファイル> 62 4257
11 CH24_2 CPP 32 <ファイル> 71 834
12 sBSDISK1 C 32 <ファイル> 73 911
13 sH24_25 C 32 <ファイル> 75 594
14 sBSDISK C 32 <ファイル> 77 840
回復するファイルの FNO. を入力してください。1
回復したいのは _2_INFO .C です。
シリンダ = 1、ヘッド = 0、セクター = 1 統合しています......
ファイルを回復するためのパスとファイル名を入力してください: c:\windows\desktop\H2_INFO.C
回復完了!!!
|
コーディングに関するコメント:
Display_Information関数は、ルートディレクトリからファイルとディレクトリの情報を読み取る関数です。構造体では、ルート[32]を持つすべてのファイルまたはディレクトリの32バイトの情報を読み取っています。
符号なし整数配列 name[8] と ext[3] は、8.3 (Eight Dot Three) 形式の DOS のファイル名またはディレクトリ名用です。同様に、1 バイトは属性用、2 バイトは開始クラスター用です。long unsigned int size; は、4 バイトのファイル サイズを格納します。
_bios_disk関数は、構造体 finfo によって指定されたセクターを読み取り、操作のステータスが result に格納されます。
_bios_disk 関数で読み取った 512 バイトの情報から、ルート ディレクトリ領域が終了するまで、ディスクに保存されているファイルとディレクトリの情報を収集し、画面に表示します。
整数 file_no には、0 から始まるリスト内のファイルまたはディレクトリの番号が格納されます。通常、ルート ディレクトリのサイズは 14 セクターで、1.44MB および 3½ フロッピー ディスクの場合、ルート ディレクトリは通常、シリンダ =0、ヘッド =0、セクター =2 から始まります。
ユーザーが入力として文字「M」または「m」を指定すると、次のセクターの情報が表示されます。ユーザーが「R」または「r」を選択した場合は、回復関数が呼び出されます。関数recover()のコーディングを以下に示します。
/*指定されたファイルの回復を開始する関数*/
void 回復(unsigned int *ルート、unsigned int 長さ)
{
void clear_the_line(unsigned int r); /* 画面上の行をクリアする関数 */
/*指定されたファイルを統合する関数*/
void integrate(long unsigned int,unsigned int,
符号なし整数、符号なし整数);
符号なし整数ファイル番号、i;
文字 ch;
符号なし整数 *loc;
unsigned int シリンダー、ヘッド、セクター;
符号なし整数 開始;
long unsigned int サイズ;
clear_the_line(21); /* 行番号21をクリアする */
clear_the_line(22); /* 行番号22をクリアする */
clear_the_line(23); /* 行番号23をクリアする */
clear_the_line(24); /* 行番号24をクリアする */
ゴトキシ(10,21);
cprintf("回復したいファイルのFNOを入力してください");
scanf("%u",&file_no); /* スキャンするファイル番号を取得します
回復しました*/
loc=(ルート+(len*file_no/2));
/*回復するファイル名を確認します*/
ゴトキシ(10,22);
cprintf("回復したい");
(i=0;i<8;i++) の場合
{
ゴトキシ(30+i,22);
cprintf("%c",*(loc+i)); /* ファイル名 */
}
ゴトキシ(38,22);
cprintf(".");
(i=0;i<3;i++) の場合
{
ゴトキシ(39+i,22);
cprintf("%c",*(loc+8+i)); /* ファイル拡張子 */
}
開始=*(loc+12);
///申し訳ありませんが、ディレクトリを選択しました\\\
(*(loc+11)==16)の場合
{
ゴトキシ(5,23);
cprintf("ディレクトリです。
このディレクトリの内容 Y/N");
ch = getch();
ch==27の場合
主要();
if(ch=='y' || ch=='Y')
{
/*ジオメトリを計算する*/
calculate(開始、&シリンダー、&ヘッド、&セクター);
/*ディレクトリの内容を表示*/
Display_Information (シリンダー、ヘッド、セクター);
}
それ以外
/* 再度ファイルを要求し、回復を続行します */
回復(ルート、長さ);
}
それ以外
{
サイズ=*(loc+13);
/* CHS 情報を計算*/
calculate(開始、&シリンダー、&ヘッド、&セクター);
/*ファイルを統合する*/
integrate(サイズ、シリンダー、ヘッド、セクター);
}
}
コーディングに関するコメント:
関数recover()は、リカバリを開始するためにユーザー入力を取得します。ファイルをリカバリするためにユーザーが入力したファイル番号は、file_noに格納されます。
入力された番号がディレクトリ エントリ用である場合、Display_Information() はそのディレクトリの内容を表示します。それ以外の場合は、回復するファイルを確認するために、ファイル番号 file_no のファイル名と拡張子が画面に表示されます。
指定されたファイルを復元するには、関数内でcalculate()関数とintegrate()関数を呼び出します。 calculate() 関数のコーディングを以下に示します。
/*回復のための CHS ジオメトリを計算する関数*/
void calculate(unsigned int start,unsigned int *cylinder,
符号なし整数 * ヘッド、符号なし整数 * セクター)
{
符号なし整数 温度;
*シリンダー=0;
*ヘッド=1;
*セクター=14;
開始<5の場合
*セクター=14+開始;
それ以外
{
温度= (開始-4)/18;
温度が0以上の場合
{
温度%2==0の場合
*ヘッド=0;
それ以外
*ヘッド=1;
*シリンダー+=1+温度/2;
}
それ以外
{
*ヘッド=0;
*シリンダー=1;
}
*セクター=(開始-4)%18;
}
///回復するファイルの CHS を表示します\\\
ゴトキシ(10,23);
cprintf("シリンダー = %u、ヘッド = %u、セクター = %u",
*シリンダー、*ヘッド、*セクター);
}
コーディングに関するコメント:
関数calculate()は、回復するファイルのシリンダ、ヘッド、およびセクター情報を計算します。計算後、シリンダ、ヘッド、およびセクターの番号が画面に表示されます。
関数 integrate() のコーディングは以下の通りです。
/*ファイルを統合し、復元したファイルを指定されたパスとファイル名に保存します*/
void integrate(long unsigned int サイズ,
符号なし整数シリンダー、
符号なし整数ヘッド、
符号なし整数セクター)
{
void clear_the_line(符号なし整数);
/*セクターのエラーを検証する関数*/
int verify_the_sector(符号なし整数, 符号なし整数,
符号なし整数);
int ステータス;
char buf[512],*ファイル名とパス;
構造体 diskinfo_t dinfo;
符号なし整数の結果;
ファイル *fp;
符号なし整数 左、i;
符号なし整数秒;
/*復元したファイルを保存する宛先パスとファイル名を入力します*/
ゴトキシ(2,24);
cprintf("ファイルを回復するにはパスとファイル名を入力してください: ");
fflush(標準入力);
ファイル名とパスを取得します。
fp=fopen(ファイル名とパス,"wb");
/*エラーが発生した場合はエラーメッセージを表示し、入力パスとファイル名を再度取得します*/
if(fp==NULL)
{
ゴトキシ(5,25);
cprintf("ファイルを開くときにエラーが発生しました");
getch();
クリア_ザ_ライン(24);
ゴトキシ(0,25);
cprintf(" ");
integrate(size,cylinder,head,sector); /* 入力してください
目的地はまたしても*/
}
/*すべてが正常であれば、統合して書き込みます*/
ゴトキシ(50,23);
cprintf("統合中......");
左=サイズ%512;
秒 = サイズ/512;
秒++;
(秒>0)の間
{
dinfo.drive = 0x00; /* A のドライブ番号: */
dinfo.head = head; /* ディスクヘッド番号 */
dinfo.track = シリンダー; /* トラック番号 */
dinfo.sector= sector; /* セクター番号 */
dinfo.nsectors=1; /* セクター数 */
dinfo.buffer = buf; /* データバッファ */
結果 = _bios_disk(_DISK_READ, &dinfo);
/* セクターの読み取り中にエラーが発生した場合 */
if( (結果 & 0xff00) != 0)
{
ゴトキシ(5,25);
cprintf("読み取りエラー シリンダ %u、ヘッド %u、セクター %u",
シリンダー、ヘッド、セクター);
}
それ以外
{
(秒==1の場合)
{
(i=0;i<left;i++) の場合
fputc(buf[i],fp); /* 統合された
ファイルへの情報 */
}
それ以外
{
fwrite(buf,512,1,fp);
}
コーディングに関するコメント:
関数integrate() は、この回復プログラムにおいて、ユーザーが指定したファイルの回復を実行する実際のモジュールです。
復元されたファイルを保存する宛先パスを含むファイル名は、文字ポインタ *Filename_with_path に格納されます。宛先ファイルを開く際にエラーが発生した場合は、エラー メッセージが表示され、ユーザーは宛先を再度入力するよう求められます。
関数_bios_disk(_DISK_READ, &dinfo); は、構造体 dinfo で指定され、データ バッファー buf に格納されているディスクのデータ領域からファイルのデータをセクターごとに読み取ります。この 512 バイトのデータは、宛先ファイルに書き込まれます。これは、ファイル全体が統合されるまで繰り返されます。
関数 status=verify_the_sector (cylinder,head,sector); は、読み取るセクターを検証します。ステータス = 10 の場合、不良 (0xA) セクターを表します。関数のコーディングを以下に示します。
///セクターを検証します。(ここではデータは転送されません) \\\
int verify_the_sector(unsigned int c,unsigned int h,unsigned int s)
{
int ステータス;
char *バッファ;
ユニオン REGS in、out;
構造体SREGSSG;
in.h.ah = 0x04; /* 関数番号 */
in.h.al = 1; /* 検証するセクター数*/
in.h.dl = 0x00; /* A のディスク番号: */
in.h.ch = c; /* シリンダー番号 */
in.h.dh = h; /* ヘッド番号 */
in.h.cl = s; /* セクター番号 */
in.x.bx = FP_OFF(buf);/* オフセット */
sg.es = FP_SEG(buf); /* セグメント */
int86x(0x13,&in,&out,&sg); /* 関数4Hを呼び出す
INT 13H から */
if(out.x.cflag)
{
ステータス=out.h.ah;
}
戻り値(ステータス);
}
コーディングコメント:
verify_the_sector() 関数は、_bios_disk() 関数によって読み取られるセクターを検証し、操作のステータスを返します。この関数は、INT 13H と関数 4H を使用してセクターをチェックします。
*buf — データ バッファ、0x04 — in.h.ah = 0x04 で指定された関数番号。そしてin.h.al = 1;一度に 1 つのセクターをチェックする必要があることを示します。 in.h.dl = 0x00;フロッピー ディスク ドライブ番号 A: に使用されます。c、h、s はシリンダー、ヘッド、セクター番号です。
int86x()関数は、セグメント レジスタ値を使用して INT 13H (関数 4H) を呼び出すために使用されます。操作ステータスは整数ステータスとして返されます。
clear_the_line()関数は、画面上の指定された行をクリアします。関数のエンコードは次のとおりです。
/*指定された行番号の画面上の行をクリアする関数*/
void clear_the_line(符号なし整数文字列)
{
符号なし整数列;
/* 1行に80列あります */
for(列=1;列<=80;列++)
{
gotoxy(列,行);
cprintf(" "); /* " " でクリア */
}
}
コーディングコメント:
この関数は、画面上の指定された行をクリアするために使用されます。この関数は、画面から消去する必要がある行番号を指定して呼び出されます。