第15章
データクリーナー向けプログラミング
導入
ディスクからファイルを削除しても、その情報はディスクから完全に消去されるわけではなく、新しいデータを書き込むために使用可能としてマークされることはすでに説明しました。
ディスクをフォーマットすると、FAT やルート ディレクトリ レコードなど、ディスクのファイルとディレクトリに関するすべての情報が消去されますが、データ領域は変更されず、ディスクのデータ領域からは何も消去されません。オペレーティング システムによって削除またはフォーマットされたデータは、データ領域にそのまま残り、データ回復の取り組みとデータ回復ソフトウェアによって回復できます。
したがって、ディスクからデータを完全に削除する必要があるため、ディスクからデータを完全に消去するプログラムが必要になります。これを行うには、単にファイルを削除したり、ディスクをフォーマットするだけでは不十分です。ディスク上のデータを他のデータで上書きする必要があります。
ディスクからデータを完全に消去するために使用されるプログラムは、データ消去プログラムと呼ばれます。これらのプログラムは、データ領域にランダムな文字を書き込んでデータを上書きし、ディスクに以前保存されたすべての情報を消去します。
データが完全に回復不能になった場合
データを消去するには、ディスク上のデータ領域を他のデータで上書きする必要がありますが、問題はそれだけでは終わりません。さらに事態を複雑にしているのは、磁気ディスクが上書きされたデータを記憶する性質上、そのデータもランダムなデータ シーケンスで複数回上書きする必要があり、高度なデータ復旧ツールを使っても復旧できないことです。
これは、今日では、いくつかの簡単なデータ削除ツールを使用した後でもデータを回復できるテクノロジーが利用可能であるためです。
一部のデータ消去製品は、データをバイナリ ゼロとバイナリ 1 で上書きします。一連のバイナリ 0 とバイナリ 1 を書き込むと、これらの値がそれぞれ最小磁気値と最大磁気値であるため、最も深い書き換え効果が得られます。
これは理想的なデータ消去プログラムの理論ですが、一般的にはランダムな ASCII 文字でデータを上書きするだけで十分です。このように言う理由は、高度な回復ツールとテクノロジーを使用した回復は、非常に高価で、1 回の回復でも数百万ドルのコストがかかるため、日常的なデータ回復のために組織のデータを回復するために使用することができないからです。それだけでなく、これらのテクノロジーは世界中のいくつかの国でしか利用できません。
ここでは、ディスクからデータを消去するための単純なデータ上書きについてのみ説明します。ただし、少しの労力で同じプログラムをさらに変更して、ランダムな文字のみを書き込むようにすることができます。このアイデアによって消去されたデータは、いかなるデータ復旧ソフトウェアでも復旧できません。
データの削除がなぜ重要なのか?
データ復旧方法について説明する際、一般的なデータ復旧方法または特別なデータ復旧方法によってデータを復旧できることをユーザーに保証します。しかし、データの回復は必ずしもすべての人にとって望ましい、期待される機能ではありません。
ディスク上のデータをいかなる方法でも復元できないように消去する用意を常にしている人や組織は数多くいるかもしれません。このような場合、ディスクには非常に機密性の高いデータが以前から含まれている可能性があり、それが悪意のある人物の手に渡ると、情報の不適切な使用により組織またはユーザーに損害を与える可能性があります。
ご存知のとおり、ハードドライブの容量に対する需要は日々高まっています。その結果、ほぼすべての組織で、毎年、古い低容量ドライブが新しい大容量ドライブに大規模に置き換えられています。これらの古いディスクが悪意のある人の手に渡った場合、この組織にとって非常に深刻な問題が発生する可能性があります。
2003 年 1 月 16 日に CNET News.com が公開したニュース記事によると、MIT の学生 Simon Garfinkel と Abby Shelat は、研究目的でインターネットやその他の中古ドライブ販売所から古いハード ドライブを購入し、人々がわざわざ削除しない膨大な個人情報にアクセスしていたとのことです。
約1,000ドルで158台のドライブを購入した後、犯人は5,000件以上のクレジットカード番号、医療記録、詳細な個人および企業の財務情報、数ギガバイトの電子メール、ソースコード、その他の情報を収集することに成功した。
この学生2人は、調査結果を「渡されたデータの記憶:ディスクの衛生管理に関する研究」と題する報告書にまとめ、IEEE Security and Privacyの2月号に掲載した。
調査から明らかになった主な点は、中古ハードドライブ市場には個人情報が溢れており、悪意のある購入者が他人の身元を偽ることが非常に容易であるという点です。
非破壊データ消去プログラムの作成
非破壊データ ワイパーは、ディスクに保存されているデータに一切害を与えることなく、ディスク ボリュームの「未割り当て領域」全体を消去できるデータ消去プログラムの一種です。
このようなデータ ワイパーの対象範囲は、ボリュームに保存されている割り当て済みデータはそのままにして、ディスク ボリュームの未割り当て領域をすべて消去したい場合です。このタイプのデータ消去プログラムは、削除されたファイルのデータ領域も消去します。
非破壊データ消去プログラムのプログラムコーディングは次のとおりです。
///// 非破壊データワイパープログラム \\\\\
#include <stdio.h>
unsigned int file_num=0; /* ファイル番号を指定します
自動作成中
一時データファイル */
float status=0; /* ディスク容量は
まだ書かれています*/
static char dbuf[40000]; /* 書き込むデータバッファ
*/ を使用した一時ファイル
char file_extension[5]=".ptt";/* 固有の拡張子
一時ファイル */
char temp[5]; /* ファイル番号を
弦 */
char filename[40]; /* 一時ファイル名 */
void main()
{
符号なし整数 i=0
clrscr()
i<40000 の場合
{
dbuf[i] = ' '
私は++
}
gotoxy(10,14);cprintf("MBはまだ書かれています...")
ながら(1)
{
/* 一意の名前で一時ファイルを自動的に作成するロジック */
strcpy(ファイル名,"TTPT")
itoa(ファイル番号、一時ファイル、10)
strcat(ファイル名,temp)
strcat(ファイル名,ファイル拡張子)
ファイル番号++
write_to_temp(ファイル名)
}
} //// メイン終了 \\\\
///// データを一時ファイルに書き込む関数 \\\\\
write_to_temp(char *ファイル名)
{
符号なし整数 i、カウント=1
buf_statusを0に設定します。
ファイル *tt
if((tt=fopen(ファイル名,"wb"))==NULL)
{
fclose(tt)
printf("\n 一時ファイルの作成中にエラーが発生しました
ファイル、 ")
printf("\n KEY BOARD後の一時ファイルの削除
打つ")
getch()
remove_temp_file();/* すべての一時ファイルを削除します */
}
ながら(1)
{
(i=0;i<50;i++) の場合
{
fprintf(tt,"%s",dbuf)
}
buf_status = (float)((40000*50*count)/512)
ステータス=ステータス+(40000*50)
カウント++
ゴトキシ(10,14)
cprintf("%.0f",(float)(status/1000000))
if(kbhit())
{
fclose(tt)
printf("\n 一時ファイルを削除しています。
待って...")
temp_file() を削除します。
}
buf_status>=10000の場合
{
fclose(tt)
戻る
}
}
}
/* 一時ファイルを自動的に削除する関数 */
一時ファイルを削除します。
{
整数 i=0
for(i=0;i<=ファイル番号;i++)
{
strcpy(ファイル名,"TTPT")
これは(i,temp,10)
strcat(ファイル名,temp)
strcat(ファイル名,ファイル拡張子)
削除(ファイル名)
}
終了(1)
0を返します。
}
プログラムのロジックとコーディングに関するコメント:
このプログラムでは、基本的に次の 2 つの手順に従って、ディスクの未割り当て領域を消去します。
- 一時データ ファイルを自動的に作成します。まず、一意の名前を持つ一時ファイルを作成し、ディスク ボリュームがこれらの一時データ ファイルでいっぱいになるまで、その中にいくつかのデータを保存します。これにより、論理ドライブの未割り当てデータ領域はすべて一時ファイルのデータで占有され、未割り当てデータはすべて上書きされます。
これを実現するために、一時ファイルの名前を TTPTxxxx.PTT 形式にしました。つまり、一時ファイルの最初の 4 文字は TTPT で、ファイルの拡張子は .PTT です。これは、一時ファイルに一意のファイル名を与えるためです。
単一の一時ファイルの最大サイズを約 11,718 セクターのデータに相当に設定しましたが、これは任意に定義できます。一時ファイルのデータを埋めるために、スペース文字「 」(ASCII 文字 32)を選択しました。ただし、スペースの代わりにランダムな文字を使用することもできます。
- すべての一時ファイルを削除: 論理ドライブが一時ファイルでいっぱいになると、未割り当てのデータ領域がすべて上書きされたことを示します。これで、プログラムによって作成されたすべての一時ファイルが自動的に削除されます。こうして、未割り当て領域の消去が達成されます。
プログラムのコーディングでは、文字配列 filename にファイル名を格納し、異なる名前で一時ファイルを自動的に生成します。
関数 write_to_temp(filename); は、40,000 バイトのデータ バッファー dbuf を使用して、一時ファイルを最大 11,718 セクター (バッファーの指定されたグループ書き込みでは 10,000 セクターは発生しないため) 相当のデータで埋めます。書き込みを高速化するために、データ バッファーは一度に 50 回書き込まれます。
一時ファイルは、ディスク ボリュームがいっぱいになり、ファイル作成エラーが発生するまで作成されます。関数 remove_temp_file() は、プログラムによって作成されたすべての一時ファイルを削除します。
この方法では、ディスク ボリュームのデータに悪影響を与えることなく、未割り当て領域がすべて消去されます。
破壊的データワイパーのプログラムの作成:
破壊的なデータ消去プログラムは、ディスクの表面に直接書き込むプログラムです。このタイプのデータ消去プログラムは、ファイル システムやオペレーティング システムよりも低いレベルで動作するため、OS、ファイル システム、ディレクトリ エントリ、およびディスクに書き込まれたすべてのデータとその他の論理情報が消去されます。
これらのデータ消去プログラムは、ディスクの表面のセクターを直接消去し、そこに書き込まれたすべてのものを消去します。オペレーティングシステムを含むディスクのすべてのデータが失われるため、これらのプログラムは破壊的データ消去プログラムと呼ばれます。
このようなタイプの消去プログラムは、ユーザーがオペレーティング システムやディスク上のすべてのデータを含むディスク上のすべてを上書きすることを希望する場合に適しています。
ただし、このタイプのデータ消去プログラムには、他にも利点があります。これらの破壊的なデータ消去プログラムは、OS やファイル システムから完全に独立して動作し、ディスクの表面に直接書き込むため、非破壊的なデータ消去プログラムよりもかなり高速です。
また、ランダム データの不正な保存によりディスク上に論理不良セクタが作成された場合でも、これらの論理不良セクタもディスクのデータとともに完全に消去されます。
次に、破壊的なデータ消去プログラムのコーディングを示します。このプログラムは、大容量のディスクもサポートするように作成されています。このプログラムは、コンピューターに接続された 2 番目の物理ハード ディスクのデータを消去します。
///// 破壊的なデータ消去プログラムのコーディング \\\\\
#include<stdio.h>
#include<dos.h>
/* INT 13H 拡張機能、関数番号 0x48 を使用して getdrivegeometry 関数によって使用される構造体。 */
構造体ジオメトリ
{
unsigned int size ; /* (呼び出し) バッファのサイズ */
unsigned int flags ; /* 情報フラグ */
unsigned long cyl; /* 物理シリンダ数
ドライブ */
unsigned long heads ;/* 物理ヘッドの数
ドライブ */
unsigned long spt; /* 物理セクター数/
追跡 */
unsigned long sectors[2] ; /* 総数
ドライブ上のセクター */
unsigned int bps ; /* セクターあたりのバイト数 */
}
/* ディスク アドレス パケット形式の構造。writeabsolutesectors 関数によって使用されます */
構造体ディスクアダーパケット
{
char packetsize ; /* パケットのサイズ、
通常10H */
char reserved ; /* 予約済み (0) */
int blockcount; /* ブロック数
移行 */
char far *bufferaddress; /* 転送先のアドレス
バッファ */
unsigned long blocknumber[2] ; /* 開始絶対値
ブロック番号 */
}
///// ドライブパラメータを取得する関数 \\\\\
符号なし long getdrivegeometry (int ドライブ)
{
ユニオン REGS i、o
構造体SREGs
構造体ジオメトリ g = { 26, 0, 0, 0, 0, 0, 0, 0, 0 }
ihah = 0x48 ; /* INT 13H の関数番号 0x48
拡張機能 */
ihdl = drive; /* ドライブ番号 */
ixsi = FP_OFF ( (void far*)&g )
s.ds = FP_SEG ( (void far*)&g )
/* セグメントレジスタ値を使用して、INT 13H拡張の指定された関数番号を呼び出します */
int86x ( 0x13, &i, &o, &s )
printf("\n ヘッド = %lu、トラックあたりのセクター数 = %lu、シリンダ数 =
%lu\n",
g.heads、g.spt、g.cyl)
/* ドライブジオメトリ取得関数が失敗した場合は、エラーメッセージを表示して終了します */
g.spt==0の場合
{
printf("\n ドライブジオメトリ取得関数が失敗しました....")
printf("\n 拡張機能はサポートされていません。任意のキーを押してください
出口...")
getch()
終了(1)
}
return *g.sectors; /* セクター数を返す
ドライブ上のセクター */
}
void main()
{
符号なしロングループ=0、Sectors_in_HDD2=0
unsigned char buffer[61440]; /* 61440のデータバッファ
バイト 相当
120セクター*/
符号なしロングi = 0
文字の選択
clrscr()
/* 接続されているハードディスクの合計数が 2 未満の場合、エラー メッセージを表示して終了します。 */
if(((char)peekb(0x0040, 0x0075))<2)
{
printf("\n\n 少なくとも2台のハードディスクが必要です
これを実行するにはコンピュータに接続してください")
printf("\n プログラム。このプログラムは開発されました
2台目のハードディスクのデータを消去します。")
printf("\n 終了するには任意のキーを押してください... ")
getch()
終了(1)
}
Sectors_in_HDD2 = getdrivegeometry (0x81)
printf(" 2番目のハードディスクの合計セクター数 =
%lu\n\n",
HDD2のセクター数)
///// 確認してから続行します \\\\\
printf("\n これはデータ消去プログラムであり、
ディスクの表面")
printf("\n このプログラムを実行した後、データは
ソフトウェアによって回復されることはありません。")
printf("\n 2台目のハードディスクにあるすべてのデータは
失った !!!")
printf("\n 続行するには\'Y\'を押してください。それ以外の場合は任意のキーを押してください
出口... ")
選択 = getche()
スイッチ(選択)
{
ケース 'y':
ケース 'Y':
壊す
デフォルト:
終了(0)
}
gotoxy(10,15);cprintf(" 初期化しています。お待ちください...")
(i=0;i<61440;i++) の場合
{
バッファ[i]='\0'
}
gotoxy(10,15);cprintf(" ")
ゴトキシ(10,15)
printf("現在絶対セクターを消去中: ")
for(ループ=0;ループ<=Sectors_in_HDD2;ループ=ループ+120)
{
絶対セクターを書き込みます(0x81、ループ、120、バッファ)
gotoxy(44,15); printf("%ld",ループ)
if(kbhit())
{
終了(0)
}
///// 完了時にメッセージを表示します \\\\\
printf("\n\n データの消去が完了しました。
2番目のハードディスクは現在")
printf("\n 完全に消去されました。終了するには任意のキーを押してください...")
getch()
}
//// 絶対セクターを書き込む関数 \\\\
int writeabsolutesectors ( int ドライブ、 unsigned long セクター番号、 int セクター数、 void *バッファ )
{
ユニオン REGS i、o
構造体SREGs
構造体ディスクアドレスパケットpp
pp.packetsize = 16 ; /* パケットサイズ = 10H */
pp.reserved = 0 ; /* 予約済み = 0 */
pp.blockcount = numofsectors ;/* ブロックするセクタ数
書かれる */
/* データバッファ用 */
pp.bufferaddress = (char far*) MK_FP ( FP_SEG((void far*)buffer), FP_OFF((void far*)buffer))
pp.blocknumber[0] = sectornumber ; /* セクター番号
書かれる*/
pp.blocknumber[1] = 0 ; /* ブロック番号 = 0 */
ihah = 0x43 ; /* 関数番号 */
ihal = 0x00 ; /* フラグ書き込み */
ihdl = drive ; /* 物理ドライブ
番号 */
ixsi = FP_OFF ( (void far*)&pp ) ; /* ds:si の場合
バッファパラメータ */
s.ds = FP_SEG ( (void far*)&pp ) ; /* ds:say の場合
バッファパラメータ */
/* セグメントレジスタ値を使用して INT 13H の指定された関数を呼び出す */
int86x ( 0x13, &i, &o, &s )
(oxcflag==1の場合)
0を返す; //失敗
それ以外
1を返す; // 成功
}
コーディングに関するコメント:
構造体ジオメトリは、INT 13H 拡張機能、関数番号 0x48 を使用して getdrivegeometry 関数によって使用され、ディスクのさまざまなパラメータを取得します。
構造体 diskaddrpacket は、writeabsolutesectors 関数で使用されるディスク アドレス パケット形式です。
関数 getdrivegeometry (int drive) は、指定された物理ドライブ番号のディスクのドライブ パラメータを取得します。バッファ [61440] は 61440 バイトのデータ バッファで、120 セクターに相当します。
(char) peekb(0x0040, 0x0075) は、セグメント 0040H:オフセット 0075H で表されるメモリ位置に格納されている、コンピュータに接続されているハード ディスクの数を検索するために使用されます。接続されているハード ディスクの合計数が 2 未満の場合は、エラー メッセージを表示して終了します。
writeabsolutesectors ( 0x81, loop, 120, buffer ) 関数は、loop で指定された絶対セクター番号から開始して、データ バッファーのデータを一度に 120 セクターに書き込むために使用されます。
データを上書きするためにセクターに書き込むために '\0' (NULL 文字、ASCII コード 0) を選択しました。ただし、ランダムな文字を使用してデータを上書きすることもできます。
writeabsolutesectors 関数と getdrivegeometry 関数の詳細な説明については、この本の前の章を参照してください。
特定のファイルのデータ領域を消去する
ディスクの未割り当て領域のデータを消去したり、ディスク全体を消去したりするデータ消去プログラムについて説明しました。しかし、ユーザーがデータを削除するたびにデータを消去したい場合、ディスクの未割り当て領域全体を消去するには時間がかかる可能性があります。
特定のファイルによって占有されているデータ領域のみを消去するには、このタイプのデータ消去プログラムが必要です。これを行うには、FATとルートディレクトリエントリを利用して、特定のファイルによって占有されているデータ領域を見つけます。
フロッピーの場合でも、データが断片化されていない場合は、ルート ディレクトリ情報を使用してのみ断片化を行うことができます。次の表は、任意のファイルについて、32 バイトのルート ディレクトリ エントリによって保存される情報を示しています。

ルート ディレクトリ エントリの目次を見ると、ファイルの開始クラスターと終了クラスターを見つけることができます。ファイル名の最初のバイトには、ファイルに関する重要な情報も含まれている場合があります。このバイトによって提供される情報は、以下のいずれかです。

この情報を使って、ルート ディレクトリ情報を利用して、1.44 MB、3 ½ インチのフロッピー ディスクに保存されているファイルのデータを消去してみましょう。フロッピー ディスクのデータが断片化されていないと仮定すると、次のプログラムは指定されたファイルのデータをそのデータ領域から消去します。
/* フロッピーディスク内の指定されたファイルのデータ領域を消去するプログラム */
#include<stdio.h>
#include<dos.h>
///// ルート ディレクトリのファイル エントリの 32 バイトを読み取るための構造 \\\\\
構造体ルート
{
unsigned char filename[8]; /* ファイル名エントリ
8 バイト */
unsigned char extension[3]; /* ファイルの拡張子
3 バイト */
unsigned char attribute; /* ファイル属性バイト */
unsigned char reserved[10]; /* 予約バイト10 */
unsigned int time; /* 時間、2 バイト */
unsigned int date; /* 日付、2 バイト */
unsigned int startup_cluster;/* ファイルの開始クラスタ、
2バイト */
unsigned long file_size; /* ファイルサイズ(バイト単位)
4バイト */
}
/* すべてのルートディレクトリエントリを読み取るにはこれを実行する必要があります */
//構造体ルートエントリ[224];
/* ルートディレクトリの 1 つのセクターにある 16 個のファイルエントリすべてを読み取るための構造 */
構造体 one_root_sector
{
構造体ルートエントリ[16]
}
構造体 one_root_sector 1
void main()
{
int 結果、i、num_sectors、j
char wipe_buf[512]; /* ワイプに使用するデータバッファ
ファイルのデータ領域を出力します */
clrscr()
result= absread(0x00, 1, 19, &one); /* 絶対セクターの読み取り
19 (ルートディレクトリの最初のセクター) */
(結果!= 0)の場合
{
perror("セクターの読み取りエラー。任意のキーを押してください。
出口...")
getch()
終了(1)
}
/* ルートディレクトリから読み込んだファイルの情報を表示する */
printf(" ファイル番号 ファイル名 拡張子 開始クラスタ
ファイルサイズ \n\n")
(i=1;i<16;i++) の場合
{
printf("\n %5d %8.8s %3.3s %5u %10lu ",
i、1つのエントリ[i].ファイル名、1つのエントリ[i].拡張子、
1.entry[i].starting_cluster、1.entry[i].file_size)
}
//// ファイルを削除するためのユーザー入力を取得します \\\\
printf("\n\n 削除したいファイル番号を入力して
完全に消去します ")
scanf("%d", &i)
i<1 || i>15 の場合
{
printf(" \"%d\"は無効な選択です...、任意のキーを押してください
終了キー...", i)
getch()
終了(1)
}
///// まず確認してから続行します \\\\\\
printf("\n あなたは全滅しようとしています、
ファイル \"%.8s.%s\"",
1.エントリ[i].ファイル名、
1.エントリ[i].拡張子)
printf("\n 続行しますか...(Y/N) ")
スイッチ(getche())
{
ケース 'y':
ケース 'Y':
壊す
デフォルト:
終了(0)
}
///// ファイルのサイズをセクター単位で計算します \\\\\
num_sectors = one.entry[i].file_size/512
if((one.entry[i].file_size%512)>0)
{
セクター数 = セクター数 + 1
}
/* 512 バイトのデータ バッファ (512 個の NULL 文字を含む) */
(j=0;j<512;j++) の場合
{
wipe_buf[j] = '\0'
}
///// ファイルの開始セクター \\\\\
j = one.entry[i].starting_cluster+31;
/* ファイルのセクターの終わりまでデータ領域を消去します */
пока(j!=(one.entry[i].starting_cluster +
セクター数+31) )
{
if((abswrite(0x00, 1, j, &wipe_buf))!=0)
{
printf("\n ディスクセクターへの書き込みエラー")
得る()
出力(0)
}
j++
}
printf("\n\n ファイル \"%.8s.%.3s\" が削除されました!!!" ,
1.エントリ[i].ファイル名、
1.エントリ[i].拡張子)
1.エントリ[i].属性 = 0; /* ファイル属性を設定する
0 に */
1.エントリ[i].時間 = 0; /* 時間情報をクリアする
ファイル */
1.エントリ[i].日付 = 0; /* 日付情報をクリアする
ファイル */
1.entry[i].starting_cluster = 0; /* 初期クラスタを0に設定する
*/
1.エントリ[i].ファイルサイズ = 0; /* ファイルサイズを 0 に設定します */
1.エントリ[i].ファイル名[0]=0xE5; /* リモートに渡す
ファイル内のファイルステータス */
///// 上記の情報をルートディレクトリに書き込みます \\\\\\
結果 = abswrite(0x00, 1, 19, &one)
(結果!= 0)の場合
{
perror("セクターの読み取りエラーです。任意のキーを押してください。
出口...")
得る()
出力(1)
}
}
プログラムのロジックとコーディングに関するコメント:
ルート構造は、ルート ディレクトリ内のファイル エントリの 32 バイトを読み取るために使用され、one_root_sector 構造は、ルート ディレクトリの 1 つのセクター内の 16 個のファイル エントリすべてを読み取ります。
ルートディレクトリ情報のすべてのセクターを読み取る場合は、それをstruct root[224]エントリとして取得する必要があります。しかし、私はルート ディレクトリの 1 つのセクターの 16 個のレコードを分析するプログラムを作成しました。
ファイルの開始セクターは次のように計算されます。
j = one.record[i].initial_cluster+31;
これは、1.44 MB、3 ½ インチのフロッピー ディスクのデータ領域がディスクの最初の 32 セクターの後に始まるためです。また、指定された容量のフロッピー ディスクでは、1 つのクラスターが 1 つのセクターに対応します。
次の表は、1.44 MB、3½ インチ フロッピー ディスクの論理マップを示しています。

プログラムの結果は次のように表示されます。

ここでは、PARTBOOT.C ファイルのデータを削除して消去しました。 DIR コマンドを使用してフロッピー ディスクの内容を表示すると、PARTBOOT.C ファイルは表示されません。プログラムをさらに実行すると、削除されたファイルのエントリが次のように表示されます。

ここで、記号「」(0xE5)は、ファイルが削除されたことを意味します。 (ファイル名の最初の文字については表を参照してください)。
同じプログラムをハードディスクに書き込む場合は、ルートディレクトリで FAT を使用して、任意のファイルのデータ領域に関する情報も取得する必要があります。
これは、古いファイルが削除され、新しいファイルが作成されるため、ハードドライブ上のデータの断片化率が時間の経過とともに増加するためです。そうすると、ディスク上のファイルのすべてのデータ クラスターがデータ領域内に連続して残る必要がなくなります。 FAT にアクセスすることで、これらすべてのクラスターにアクセスできます。