第 10 章
从损坏的软盘中恢复数据
从损坏的软盘中恢复数据
软盘是最不可靠的数据存储来源之一。如果你去任何使用计算机系统的组织并向其员工询问软盘产生的问题,你通常会听到这样的问题,即该组织的员工的软盘中有一些重要数据,而现在软盘没有了。计算机可读,并显示类似的消息,
“无法读取磁盘”
“跟踪 0 坏”
“无效的驱动器或容量”
“磁盘未格式化。你想现在格式化吗?”
这是使用计算机系统和软盘的组织的日常问题。当您知道没有备份或备份似乎丢失在损坏的软盘中的数据时,问题变得至关重要。
当您在软盘中备份您的关键信息时,最大的问题应该来了,防病毒程序的救援盘以克服病毒攻击或启动记录或其他备份(可能有很多可能性)软盘,当您想重新使用软盘中的备份时,会出现读取错误。
在这种情况下,您将丢失您的重要信息和数据,甚至在某些情况下,您会感到缺少备份和恢复程序为您的计算机启动信息和病毒攻击救援程序等,您可能会因缺少信息而发生操作系统崩溃的数据丢失,存储在计算机无法读取的软盘中。
在这种情况下,最重要的要求是恢复软盘中的数据,该软盘已被您的计算机系统宣布为损坏。
为什么软盘不可读
导致软盘显示此类错误消息的最常见问题是软盘的 DOS 引导记录 (DBR) 损坏,这有助于计算机了解软盘的逻辑标识。
DBR 是一个小程序,存储在磁道 0、磁头 0 和扇区 1 中,包含有关软盘的重要信息,例如:
- 每个扇区的字节数
- 每个集群的扇区
- FAT 数量
- 最大根目录数等
由于软盘没有逻辑分区系统,因此软盘中没有可用的 MBR。软盘的第一部门持有 DBR。这也是比较硬盘和软盘逻辑结构的主要区别。
当我们借助任何磁盘编辑程序读取软盘的引导扇区信息时,它会显示如下图所示的信息。
下图是一个1.44MB的DBR的512Bytes信息,3½英寸软盘。
如果此信息以任何方式损坏或变得无法读取,软盘会导致此类读取错误消息。这可能是由于磁盘第一个扇区的物理或逻辑损坏。
逻辑损坏包括软盘第一个扇区的信息发生变化,出现逻辑坏扇区或DBR的情况 软盘由于任何其他原因损坏。
物理损坏应该发生在以下情况下,如果有 物理坏扇区(意味着扇区 1 物理损坏)软盘。当您发现软盘在磁道 0 中有多个坏扇区时,问题会变得更加严重。
如何恢复
我们已经了解了腐败的两个原因,我希望您现在能够理解这个问题。 从逻辑损坏中恢复数据并不是一件很困难的事情,但是从物理损坏中恢复需要稍加努力。
方法 – 1
存储任何新软盘的启动映像
如果问题是合乎逻辑的,那么现在我们了解如何恢复数据。我们需要做的只是从另一张相同大小和容量的软盘中获取适当的引导记录,并将其粘贴到无法读取的软盘的第一个扇区。虽然问题是由于糟糕的引导记录造成的,但它现在应该可以工作了。
此过程涉及两个步骤,我们将从不可读的软盘中恢复我们的数据:
- 制作好软盘的DOS引导记录映像
- 将启动映像粘贴到不可读软盘的第一个扇区
制作好软盘的DOS引导记录映像
要存储新软盘的引导记录映像,程序必须完成以下三个任务:
- 准确读取好软盘的前 512 个字节
- 检查读取操作是否成功(最重要)
- 将这 512 个字节存储到指定的文件名和目标路径
软盘的扇区为 512 字节,需要复制扇区的准确映像。在软盘上进行任何类型的操作时,检查操作是否成功是最重要和必要的一步。
即使是新软盘也可能存在初始化问题。这就是为什么在大多数情况下,在对软盘进行操作时,首先在编程中使用复位磁盘操作(INT 13H 的00 H 功能)对软盘进行初始化。
如果即使在初始化后最近插入的软盘或更换的软盘导致任何读取错误,建议您再次运行该程序,这一次很可能它可以工作。
下面的程序就是执行这些指定的任务。让我们看看它是如何进行的:
/* 将启动映像从新软盘存储到文件中 */
#include <bios.h>
#include <stdio.h>
int main(void)
{
struct diskinfo_t dinfo;
union REGS regs;
int result;
int count=0, i;
char fname[80];
static char dbuf[512];
FILE *fp;
dinfo.drive = 0x00; /* drive number for A: */
dinfo.head = 0; /* disk head number */
dinfo.track = 0; /* track number */
dinfo.sector = 1; /* sector number */
dinfo.nsectors = 1; /* sector count */
dinfo.buffer = dbuf; /* data buffer */
clrscr();
gotoxy(10,3);cprintf("Enter The File Name And Path To
Store Boot Image");
gotoxy(5,5);
gets(fname);
fp=fopen(fname,"wb");
if((fp=fopen(fname,"wb"))==NULL)
{
highvideo();
gotoxy(10,10);cprintf("File Could Not Be created");
getch();
exit(0);
}
gotoxy(10,9);
cprintf("Attempting to read from Floppy disk drive :\n");
/// 初始化磁盘系统 \\\
for(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Reset Disk System */
regs.h.dl = 0x00; /* Floppy Disk a: */
int86(0x13, ®s, ®s);
}
result = _bios_disk(_DISK_READ, &dinfo);
if ((result & 0xff00) == 0)
{
while(count<512)
{
fprintf(fp,"%c",dbuf[count] & 0xff );
count++;
}
fclose(fp);
gotoxy(10,14);cprintf("Disk read from Floppy disk drive
: successful.\n");
}
else
{
gotoxy(10,14);
cprintf("Cannot read drive A, status = 0x%02x\n", result);
switch(result)
{
case 0x00:
cprintf("\n\n STATUS: No Error!!");
break;
case 0x01:
cprintf("\n\n STATUS: Bad command");
break;
case 0x02:
cprintf("\n\n STATUS: Address mark not found");
break;
case 0x03:
cprintf("\n\n STATUS: Attempt to write to write-protected disk");
break;
case 0x04:
cprintf("\n\n STATUS: Sector not found");
break;
case 0x06:
cprintf("\n\n STATUS: Disk changed since last operation");
break;
case 0x08:
cprintf("\n\n STATUS: Direct memory access (DMA) overrun");
break;
case 0x09:
cprintf("\n\n STATUS: Attempt to perform DMA across 64K boundary");
break;
case 0x0C:
cprintf("\n\n STATUS: Media type not found");
break;
case 0x10:
cprintf("\n\n STATUS: Bad CRC/ECC on disk read");
break;
case 0x20:
cprintf("\n\n STATUS: Controller has failed");
break;
case 0x31:
cprintf("\n\n STATUS: No media in drive (IBM/MS INT 13H extensions)");
break;
case 0x32:
cprintf("\n\n STATUS: Incorrect drive type stored in CMOS (Compaq)");
break;
case 0x40:
cprintf("\n\n STATUS: Seek operation failed");
break;
case 0x80:
cprintf("\n\n STATUS: Attachment failed to respond(Disk Timed-out)");
break;
case 0xB0:
cprintf("\n\n STATUS: Volume not locked in drive (INT 13H extensions)");
break;
case 0xB1:
cprintf("\n\n STATUS: Volume locked in drive (INT 13H extensions)");
break;
case 0xB2:
cprintf("\n\n STATUS: Volume not removable (INT 13H extensions)");
break;
case 0xB3:
cprintf("\n\n STATUS: Volume in use (INT 13H extensions)");
break;
case 0xB4:
cprintf("\n\n STATUS: Lock count exceeded (INT 13H extensions)");
break;
case 0xB5:
cprintf("\n\n STATUS: Valid eject request failed (INT 13H extensions)");
break;
default: cprintf("\n\n STATUS: UNKNOWN Status CODE For Floppy Errors");
}
}
return 0;
}
程序编码评论:
在前面给出的程序编码中,基本上我们是在一步步执行以下任务:
- dinfo 指向diskinfo_t 结构,该结构包含_bios_disk 函数执行的操作所需的参数信息。
- 因为我们要读取磁盘的第一个扇区,所以扇区的位置如下:
Parameter |
What it means |
dinfo.drive = 0x00 |
It indicates the drive 0 that is floppy disk drive (a:) |
dinfo.head = 0 |
It points to head number 0 |
dinfo.track = 0 |
It points to track 0 |
dinfo.sector = 1 |
First sector of the floppy that is sector 1 |
dinfo.sector = 1 |
Number of sectors to consider for read operation = 1 |
dinfo.buffer = dbuf |
Data buffer for the operation |
- 打开用户给定文件名和路径的文件流,以存储精确的 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) 读取软盘的指定扇区。
- 返回的状态存储在 result 中,用于显示操作成功的消息或在出现错误时在屏幕上显示错误消息。
将启动映像粘贴到不可读软盘的第一个扇区
为了将启动映像从文件粘贴到不可读软盘的第一个扇区,我们必须在程序中执行以下三个主要任务:
- 从以前保存的文件中读取新软盘启动记录的准确 512 字节信息。
- 将此信息写入软盘当前不可读的第一个扇区。
- 检查写入操作是否成功完成(最重要)。
由于软盘的扇区是 512 字节,因此需要将准确的引导映像粘贴到该扇区。在软盘上应用任何类型的操作时,检查操作是否成功是最重要和必要的一步。
软盘在操作过程中可能会出现初始化问题,因此您必须通过重置磁盘系统(使用INT 13H的00H函数)来初始化磁盘。
如果即使在初始化后最近插入的软盘或更换的软盘导致任何读取错误,建议您再次运行该程序,这一次很可能它可以工作。
下面的程序就是执行这些指定的任务。让我们看看它是如何进行的:
/* 将启动映像加载到不可读的软盘 */
#include <bios.h>
#include <stdio.h>
int main(void)
{
struct diskinfo_t dinfo;
union REGS regs;
int result;
int count=0, i;
char fname[80];
char dbuf[512];
FILE *fp;
clrscr();
gotoxy(5,3);cprintf("Enter The File Name And Path, In Which Boot image of Floppy Is Stored");
gotoxy(5,5);
gets(fname);
fp=fopen(fname,"rb");
if((fp=fopen(fname,"rb"))==NULL)
{
highvideo();
gotoxy(10,10);cprintf("File Could Not Be Opened");
getch();
exit(0);
}
gotoxy(10,9);
cprintf("Attempting to Recover Floppy disk drive :\n");
/// 初始化磁盘系统 \\\
for(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Reset Disk System */
regs.h.dl = 0x00; /* Floppy Disk a: */
int86(0x13, ®s, ®s);
}
while(count<512)
{
fscanf(fp,"%c",&dbuf[count]);
count++;
}
dinfo.drive = 0x00; /* drive number for A: */
dinfo.head = 0; /* disk head number */
dinfo.track = 0; /* track number */
dinfo.sector = 1; /* sector number */
dinfo.nsectors = 1; /* sector count */
dinfo.buffer = dbuf; /* data buffer */
result = _bios_disk(_DISK_WRITE, &dinfo);
if ((result & 0xff00) == 0)
{
fclose(fp);
gotoxy(10,14);cprintf("Successful!!! I Hope Floppy May
Work Now.\n");
}
else
{
gotoxy(10,14);
cprintf("Cannot read drive A, status = 0x%02x\n",result);
gotoxy(10,16);
switch(result)
{
case 0x00:
cprintf("\n\n STATUS: No Error!!");
break;
case 0x01:
cprintf("\n\n STATUS: Bad command");
break;
case 0x02:
cprintf("\n\n STATUS: Address mark not found");
break;
case 0x03:
cprintf("\n\n STATUS: Attempt to write to write-protected disk");
break;
case 0x04:
cprintf("\n\n STATUS: Sector not found");
break;
case 0x06:
cprintf("\n\n STATUS: Disk changed since last operation");
break;
case 0x08:
cprintf("\n\n STATUS: Direct memory access (DMA) overrun");
break;
case 0x09:
cprintf("\n\n STATUS: Attempt to perform DMA across 64K boundary");
break;
case 0x0C:
cprintf("\n\n STATUS: Media type not found");
break;
case 0x10:
cprintf("\n\n STATUS: Bad CRC/ECC on disk read");
break;
case 0x20:
cprintf("\n\n STATUS: Controller has failed");
break;
case 0x31:
cprintf("\n\n STATUS: No media in drive (IBM/MS INT 13H extensions)");
break;
case 0x32:
cprintf("\n\n STATUS: Incorrect drive type stored in CMOS (Compaq)");
break;
case 0x40:
cprintf("\n\n STATUS: Seek operation failed");
break;
case 0x80:
cprintf("\n\n STATUS: Attachment failed to respond(Disk Timed-out)");
break;
case 0xB0:
cprintf("\n\n STATUS: Volume not locked in drive (INT 13H extensions)");
break;
case 0xB1:
cprintf("\n\n STATUS: Volume locked in drive (INT 13H extensions)");
break;
case 0xB2:
cprintf("\n\n STATUS: Volume not removable (INT 13H extensions)");
break;
case 0xB3:
cprintf("\n\n STATUS: Volume in use (INT 13H extensions)");
break;
case 0xB4:
cprintf("\n\n STATUS: Lock count exceeded (INT 13H extensions)");
break;
case 0xB5:
cprintf("\n\n STATUS: Valid eject request failed (INT 13H extensions)");
break;
default: cprintf("\n\n STATUS: UNKNOWN Status CODE For Floppy Errors");
}
}
return 0;
}
程序编码评论:
在前面给出的程序编码中,基本上我们是在一步步执行以下任务:
- dinfo指向diskinfo_t结构体,该结构体包含_bios_disk函数执行操作所需的参数信息。
- 由于我们要在磁盘的第一个扇区写入信息,因此扇区的位置如下:
- 打开前一个程序保存了一张新软盘的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) 将引导信息从指定文件写入软盘的第一个(指定)扇区。
- 返回的状态存储在 result 中,用于显示操作成功的消息或在出现错误时在屏幕上显示错误消息。
Parameter |
What it means |
dinfo.drive = 0x00 |
It indicates the drive 0 that is floppy disk drive (a:) |
dinfo.head = 0 |
It points to head number 0 |
dinfo.track = 0 |
It points to track 0 |
dinfo.sector = 1 |
First sector of the floppy that is sector 1 |
dinfo.sector = 1 |
Number of sectors to consider for write operation = 1 |
dinfo.buffer = dbuf |
Data buffer for the operation |
让我们用单个程序来做
我希望,现在您已经了解了这种从软盘恢复数据背后的概念。在此之后,让我们想象一个程序,它给出的结果与我们在前面讨论的两个程序的帮助下得到的结果相同。
我们对最近讨论的程序执行了以下任务:
- 将启动信息从一张好的软盘存储到一个文件中
- 将此信息粘贴到当前无法读取的软盘的第一个扇区 我们用来存储启动映像的文件作为中间桥连接两个程序的操作。但是如果我们在程序编码本身中定义了这个引导信息,我们就不需要创建一个文件,也不需要从文件中读取软盘的引导信息。
在我们的下一个程序中,我们将告诉我们的程序它必须在不可读的软盘的第一个扇区中写入什么,因此我们能够避免两个不同的程序执行相同的任务,并且我们可以恢复我们的数据以与以前相同的方式从新的单个程序中获取。
程序因此变得简单,编码更少,我们能够降低文件读取、写入或创建错误的发生概率。在这个计划中,我们正在执行以下四项重要任务:
不要以为看到 512 的程序很难写和理解dbuf[512]的字节十六进制信息。稍后,我们将讨论为您的程序编码编写此信息的简单方法。
- 定义要写入当前不可读软盘第一个扇区的十六进制DOS引导记录信息。
- 重置磁盘系统以初始化软盘(INT 13H,Function 00H)。
- 将 DOS 引导记录写入软盘的第一个扇区
- 检查操作是否成功完成,如果发生错误.
让我们检查一下程序:
/* 将默认启动映像加载到不可读软盘的单个程序 */
#include <bios.h>
#include <stdio.h>
int main(void)
{
struct diskinfo_t dinfo;
union REGS regs:
int result, i;
/* 要加载到软盘驱动器中的引导映像 */
static 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,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,0 x72,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,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; /* drive number for A: */
dinfo.head = 0; /* disk head number */
dinfo.track = 0; /* track number */
dinfo.sector = 1; /* sector number */
dinfo.nsectors = 1; /* sector count */
dinfo.buffer = dbuf; /* data buffer */
gotoxy(10,9);
cprintf("Attempting to read from Floppy disk drive :\n");
/// 初始化磁盘系统 \\\
for(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Reset Disk System */
regs.h.dl = 0x00; /* Floppy Disk a: */
int86(0x13, ®s, ®s);
}
result = _bios_disk(_DISK_WRITE, &dinfo);
if ((result & 0xff00) == 0)
{
gotoxy(10,14);
cprintf("Disk Write Status :successful.\n");
}
else
{
gotoxy(10,14);
cprintf("Cannot read drive A, status = 0x%02x\n",
result);
gotoxy(10,16);
switch(result)
{
case 0x00:
cprintf("\n\n STATUS: No Error!!");
break;
case 0x01:
cprintf("\n\n STATUS: Bad command");
break;
case 0x02:
cprintf("\n\n STATUS: Address mark not found");
break;
case 0x03:
cprintf("\n\n STATUS: Attempt to write to write-
protected disk");
break;
case 0x04:
cprintf("\n\n STATUS: Sector not found");
break;
case 0x06:
cprintf("\n\n STATUS: Disk changed since last operation");
break;
case 0x08:
cprintf("\n\n STATUS: Direct memory access (DMA) overrun");
break;
case 0x09:
cprintf("\n\n STATUS: Attempt to perform DMA across 64K boundary");
break;
case 0x0C:
cprintf("\n\n STATUS: Media type not found");
break;
case 0x10:
cprintf("\n\n STATUS: Bad CRC/ECC on disk read");
break;
case 0x20:
cprintf("\n\n STATUS: Controller has failed");
break;
case 0x31:
cprintf("\n\n STATUS: No media in drive (IBM/MS INT 13H extensions)");
break;
case 0x32:
cprintf("\n\n STATUS: Incorrect drive type stored in CMOS (Compaq)");
break;
case 0x40:
cprintf("\n\n STATUS: Seek operation failed");
break;
case 0x80:
cprintf("\n\n STATUS: Attachment failed to respond(Disk Timed-out)");
break;
case 0xB0:
cprintf("\n\n STATUS: Volume not locked in drive (INT 13H extensions)");
break;
case 0xB1:
cprintf("\n\n STATUS: Volume locked in drive (INT 13H extensions)");
break;
case 0xB2:
cprintf("\n\n STATUS: Volume not removable (INT 13H extensions)");
break;
case 0xB3:
cprintf("\n\n STATUS: Volume in use (INT 13 extensions)");
break;
case 0xB4:
cprintf("\n\n STATUS: Lock count exceeded (INT 13H extensions)");
break;
case 0xB5:
cprintf("\n\n STATUS: Valid eject request failed (INT 13H extensions)");
break;
default: cprintf("\n\n STATUS: UNKNOWN Status CODE For Floppy Errors");
}
}
return 0;
}
在这个程序编码中,基本上我们是在逐步执行以下这些任务:
- 静态字符数据缓冲区dbuf[512]提供16进制的512字节信息,写入不可读软盘的第一个扇区。 dbuf[512] 在操作过程中告诉计算机哪些信息将被写入软盘的第一个扇区。 (见下一个节目)
- dinfo指向diskinfo_t结构,该结构包含_bios_disk函数执行操作所需的参数信息。
- 由于我们要在磁盘的第一个扇区写入信息,因此扇区的位置如下:
Parameter |
What it means |
dinfo.drive = 0x00 |
It indicates the drive 0 that is floppy disk drive (a:) |
dinfo.head = 0 |
It points to head number 0 |
dinfo.track = 0 |
It points to track 0 |
dinfo.sector = 1 |
First sector of the floppy that is sector 1 |
dinfo.sector = 1 |
Number of sectors to consider for write operation = 1 |
dinfo.buffer = dbuf |
Data buffer for the operation |
- 使用中断 13H(函数 00h)初始化磁盘系统,其中 regs.h.ah = 0x00 指向函数 00 H,而 regs.h.dl = 0x00 用于 a:软盘。并且 int86(0x13, ®s, ®s) 调用 MS-DOS 中断服务 INT 13 H。
- _bios_disk(_DISK_WRITE, &dinfo) 将引导信息从指定文件写入软盘的第一个(指定)扇区。
返回的状态存储在result中,用于显示操作成功的信息或出现错误时在屏幕上显示错误信息。
以 HEXADECIMAL 字符存储启动图像以在我们之前的程序中使用
在我们最近讨论的程序中,要手动将软盘的 DOS 引导记录的 512 个字符全部写入 16 进制而不出现任何错误,将是一项非常困难的工作。如果我们能准确地写出来,那将是一项艰巨且耗时的任务。让我们用一些技巧将数据缓冲区 dbuf[512] 的数据存储在一个文件中。
我们知道在 C 编程中十六进制字符用 0x 表示,因此如果十六进制字符是 A9 H,我们将在 C 程序中将其写为 0xA9。我们的下一个程序也在做同样的事情。它将存储我们之前程序中需要写入的数据,作为数据缓冲区dbuf[512]的数据。
你所要做的就是拿一张新的软盘来制作它的 DBR 的映像,然后从指定的目标文件中复制这个程序的输出,然后把这个数据粘贴到你的程序中。如果需要,请进行一些格式化。让我们看看它是如何工作的:
/* 用十六进制字符制作软盘启动映像的程序 */
#include <bios.h>
#include <stdio.h>
int main(void)
{
struct diskinfo_t dinfo;
union REGS regs;
int result,i;
int count=0;
char fname[80];
static char dbuf[512];
FILE *fp;
dinfo.drive = 0x00; /* drive number for A: */
dinfo.head = 0; /* disk head number */
dinfo.track = 0; /* track number */
dinfo.sector = 1; /* sector number */
dinfo.nsectors = 1; /* sector count */
dinfo.buffer = dbuf; /* data buffer */
clrscr();
gotoxy(10,3);cprintf("Enter The File Name And Path To
Store The Boot Image in HEX System");
gotoxy(5,5);
gets(fname);
fp=fopen(fname,"wb");
if((fp=fopen(fname,"wb"))==NULL)
{
highvideo();
gotoxy(10,10);cprintf("File Could Not Be created");
getch();
exit(0);
}
/// 初始化磁盘系统 \\\
for(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Reset Disk System */
regs.h.dl = 0x00; /* Floppy Disk a: */
int86(0x13, ®s, ®s);
}
gotoxy(10,9); cprintf("Attempting to read from Floppy
disk drive :\n");
result = _bios_disk(_DISK_READ, &dinfo);
if ((result & 0xff00) == 0)
{
gotoxy(10,14);
cprintf("Disk read from Floppy disk drive :
successful.\n");
while(count<512)
{
fprintf(fp,"0x%X, ",dbuf[count] & 0xff );
count++;
}
fclose(fp);
}
else
{
gotoxy(10,14);
cprintf("Cannot read drive A, status = 0x%02x\n",
result);
}
return 0;
}
对程序编码的评论:
因此数据存储在指定的文件中。只需将数据复制到您的程序并进行一些必要的格式化。在整个过程中,您永远不应忘记以下提示:
- 确保程序运行成功,并且已存储在目标文件中的数据正确。
- 您应该检查操作是否出现预期错误。
- 您必须先用程序初始化软盘,然后才能读取其引导扇区。为此,您可以使用 INT 13H 的函数 00H.
方法 – 2
如果方法–怎么办? 1 不起作用?
如果方法 – 1 不起作用并且不可读的磁盘不允许程序在其第一个扇区上重新写入引导信息,您应该尝试第二种方法。第一种方法失败的原因可能是软盘第一扇区物理损坏。
在第二种方法中,我们将暂时将无法读取的软盘表面的所有数据复制到一个文件中,然后将这个图像直接粘贴到另一个好磁盘的表面上。
该过程涉及以下两个重要步骤:
- 逐扇区将软盘介质表面的所有数据临时复制到一个文件中。
- 将之前存储在文件中的数据粘贴到新软盘的相同扇区上。
将媒体表面的所有数据复制到一个文件中
要存储软盘介质表面的所有数据,程序必须完成以下三个任务:
- 借助 INT 13H 的 00H 函数正确初始化磁盘。
- 读取表面的逐扇区信息并存储到单个文件中。
- 检查读取操作是否成功(最重要)
软盘初始化问题是很常见的,这会导致许多不成功的读取消息。这就是为什么在读写操作之前必须借助编程对磁盘进行初始化。
在软盘上进行任何类型的操作时,检查操作是否成功是最重要和必要的一步。
如果即使在初始化后最近插入的软盘或更换的软盘导致任何读取错误,建议您再次运行该程序,这一次很可能它可以工作。
下面的程序就是执行这些指定的任务。让我们看看它是如何进行的:
/* 将软盘物理表面的数据存储到文件中的程序 */
#include <bios.h>
#include <stdio.h>
void main(void)
{
int head,track;
union REGS regs;
int result,i,sector;
char filename[80];
struct diskinfo_t dinfo;
static char dbuf[512];
FILE *tt;
clrscr();
printf("\n Enter The Name of file with Path to store The
Data Temporarily\n");
gets(filename);
if((tt=fopen(filename,"wb"))==NULL)
{
printf("Could Not Create The File,
Press any Key To EXIT");
getch();
exit(0);
}
printf("\n Initializing Floppy Disk System...\n");
/// 初始化磁盘系统 \\\
for(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Reset Disk System */
regs.h.dl = 0x00; /* Floppy Disk a: */
int86(0x13, ®s, ®s);
}
for(track=0;track<=79;track++)
{
for(head=0;head<=1;head++)
{
for(sector=1;sector<=18;sector++)
{
dinfo.drive = 0; /* drive number for A: */
dinfo.head = head; /* disk head number */
dinfo.track = track; /* track number */
dinfo.sector = sector; /* sector number */
dinfo.nsectors = 1; /* sector count */
dinfo.buffer = dbuf; /* data buffer */
result = _bios_disk(_DISK_READ, &dinfo);
if ((result & 0xff00) == 0)
{
for(i=0;i<512;i++)
fprintf(tt,"%c",dbuf[i] & 0xff);
}
else
{
printf("Cannot read drive A, status =
0x%02x\t%d\t%d\t%d\n", result,head,track,sector);
}
printf("Reading Track= %d Head= %d Sector= %d\n",
track,head,sector);
}
}
}
}
程序编码评论:
在前面给出的程序编码中,基本上我们是在一步步执行以下任务:
- 字符数组文件名[80] 存储用户定义的路径和我们将临时存储数据的文件的文件名。
- dinfo 指向diskinfo_t 结构,该结构包含_bios_disk 函数执行的操作所需的参数信息。
- 使用中断 13H(函数 00h)初始化磁盘系统,其中 regs.h.ah = 0x00 指向函数 00 H,regs.h.dl = 0x00 用于:软盘。并且 int86(0x13, ®s, ®s) 调用 MS-DOS 中断服务 INT 13 H。
- 由于我们要读取磁盘表面的所有信息,_bios_disk的参数如下:
Parameter |
What it means |
dinfo.drive = 0x00 |
It indicates the drive 0 that is floppy disk drive (a:) |
dinfo.head = head |
It points to head number 0 and 1 as floppy has two sides(two heads) |
dinfo.track = track |
It points to track 0 to 79 as there are 80 tracks on each side of floppy. |
dinfo.sector = sector |
It points to sector 1 to 18 as there are 18 sectors in each track. |
dinfo.sector = 1 |
Number of sectors to consider for read operation = 1 |
dinfo.buffer = dbuf |
Data buffer for the operation |
- _bios_disk(_DISK_READ, &dinfo) 从 dinfo 指定的扇区读取软盘物理表面的数据。
- 返回的状态存储在 result 中,用于显示操作成功的消息或出现错误时在屏幕上显示错误消息.
永远记住,保存软盘数据映像的文件大小必须精确为 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 head,track;
union REGS regs;
int result,i,sector;
char filename[80];
struct diskinfo_t dinfo;
static char dbuf[512];
/*填充坏扇区空间的 512 字节信息 */
/// 我用了 512 个零来填充 512 个字节的空间 \\\
static char dbuf2[512] =
"00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000";
FILE *tt;
clrscr();
printf("\n Enter The Name of file with Path to store The
Data Temporarily\n");
gets(filename);
if((tt=fopen(filename,"wb"))==NULL)
{
printf("Could Not Create The File, Press any Key To
EXIT");
getch();
exit(0);
}
printf("\n Initializing Floppy Disk System...\n");
/// 初始化磁盘系统 \\\
for(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Reset Disk System */
regs.h.dl = 0x00; /* Floppy Disk a: */
int86(0x13, ®s, ®s);
}
for(track=0;track<=79;track++)
{
for(head=0;head<=1;head++)
{
for(sector=1;sector<=18;sector++)
{
dinfo.drive = 0; /* drive number for A: */
dinfo.head = head; /* disk head number */
dinfo.track = track; /* track number */
dinfo.sector = sector; /* sector number */
dinfo.nsectors = 1; /* sector count */
dinfo.buffer = dbuf; /* data buffer */
result = _bios_disk(_DISK_READ, &dinfo);
if ((result & 0xff00) == 0)
{
for(i=0;i<512;i++)
fprintf(tt,"%c",dbuf[i] & 0xff);
}
else
{
printf("Cannot read drive A, status =
0x%02x\t%d\t%d\t%d\n", result, head, track, sector);
/* 如果 Sector 不可读,则由 dbuf2 占用 512 字节 */
fwrite(dbuf2,512,1,tt);
}
printf("Reading Track= %d Head= %d Sector= %d\n",
track, head, sector);
}
}
}
}
程序编码评论:
在程序的编码中,除了数据缓冲区dbuf2[512]之外,每个步骤都与之前的程序相同,我们使用它来处理磁盘读取操作期间由坏扇区产生的错误 并保持图像文件的大小。
通过这样做,我们正在填充我们未能从坏扇区读取的信息空间,现在我们正在写入512字节的伪信息以便我们可以保持磁盘映像的准确性。
将文件中的数据粘贴到新软盘的物理表面:
在这一步中,我们将前一个程序存储在文件中的数据粘贴到新软盘的物理表面,逐个扇区地粘贴到文件中。
程序执行以下主要步骤:
- 打开我们临时存储不可读软盘表面数据的文件。
- 通过INT 13H的复位函数00H正确初始化磁盘系统。
- 从文件中写入新软盘的扇区信息。
- 同时显示写入状态,以发现或避免错误的发生.
程序源代码已在下面给出。让我们看看它是如何工作的:
/* 程序将数据写入上一个程序创建的文件中的新鲜软盘表面的扇区 */
#include <bios.h>
#include <stdio.h>
void main(void)
{
int head,track;
union REGS regs;
int result,i,sector;
int count =0;
char filename[80];
struct diskinfo_t dinfo;
static char dbuf[512];
FILE *fp;
clrscr();
printf("\n Enter The Name of file with Path to store The
Data Temporarily\n");
gets(filename);
if((fp=fopen(filename,"rb"))==NULL)
{
printf("Could Not Create The File, Press any Key To
EXIT");
getch();
exit(1);
}
/// 初始化磁盘系统 \\\
for(i=0; i<3; i++)
{
regs.h.ah = 0x00; /* Reset Disk System */
regs.h.dl = 0x00; /* Floppy Disk a: */
int86(0x13, ®s, ®s);
}
for(track=0;track<=79;track++)
{
for(head=0;head<=1;head++)
{
for(sector=1;sector<=18;sector++)
{
count =0;
while(count<512 )
{
fscanf(fp,"%c",&dbuf[count]);
count++;
}
dinfo.drive = 0x00; /* drive number for A: */
dinfo.head = head; /* disk head number */
dinfo.track = track; /* track number */
dinfo.sector = sector;/* sector number */
dinfo.nsectors = 1; /* sector count */
dinfo.buffer = dbuf; /* data buffer */
result= _bios_disk(_DISK_WRITE, &dinfo);
if ((result & 0xff00) == 0)
printf("Successful write on Track = %d, Head = %d,
Sector = %d.\n", track, head, sector);
else
printf("Cannot read drive A, status = 0x%02x\n",
result);
}
}
}
}
程序编码评论:
在前面给出的程序编码中,基本上我们是在一步步执行以下任务:
- 字符数组filename[80]保存了我们临时存放不可读软盘表面数据的文件的路径和文件名。
- dinfo指向diskinfo_t结构体,该结构体包含_bios_disk函数执行操作所需的参数信息。
- 使用中断 13H(函数 00h)初始化磁盘系统,其中 regs.h.ah = 0x00 指向函数 00 H,而 regs.h.dl = 0x00 用于:软盘。并且 int86(0x13, ®s, ®s) 调用 MS-DOS 中断服务 INT 13 H。
- 由于我们要将信息直接写入磁盘表面的扇区,_bios_disk的参数如下:
Parameter |
What it means |
dinfo.drive = 0x00 |
It indicates the drive 0 that is floppy disk drive (a:) |
dinfo.head = head |
It points to head number 0 and 1 as floppy has two sides(two heads) |
dinfo.track = track |
It points to track 0 to 79 as there are 80 tracks on each side of floppy. |
dinfo.sector = sector |
It points to sector 1 to 18 as there are 18 sectors in each track. |
dinfo.sector = 1 |
Number of sectors to consider for write operation = 1 |
dinfo.buffer = dbuf |
Data buffer for the operation |
- _bios_disk(_DISK_WRITE, &dinfo) 将数据写入软盘物理表面的扇区,由 dinfo 指定。
- 返回的状态存储在 result 中,用于显示操作成功的消息或出现错误时在屏幕上显示错误消息.
如果在方法之后 – 2 你的新软盘不工作,你可以进一步申请方法– 1 在您的新软盘上,您在方法期间将其用作目标磁盘 – 2.
不仅如此,命中和试验的数量也可能因磁盘损坏而异。但是,即使您没有得到满意的结果,您也不必担心。
您可以尝试逐个文件恢复,也可以尝试更多技巧,这些技巧将在接下来学习。在这里,我们将实现从根目录中收集文件信息的想法,在我们的程序中恢复数据。
考虑对已删除或丢失的数据进行逻辑恢复:
我们在本章中讨论的所有先前恢复案例都是在我们预计只有 DBR 损坏和扇区的情况下恢复数据在磁道 0 中,具有 FAT1、FAT2 和 根目录可读。
但如果问题是由于FAT损坏或数据已从磁盘中删除或您想恢复数据直接通过读取其信息从根目录,我们需要读取文件名、启动集群、文件大小等信息,属性等从它的根目录条目。
正如我们在前面章节中已经讨论过的根目录,每个文件或目录都有 32 字节的信息。这 32 个 Bytes 划分如下:
Number of Bytes |
Information Description |
8 Bytes |
Filename |
3 Bytes |
Extension |
1 Byte |
Attribute |
10 Bytes |
Reserved |
2 Bytes |
Time, Created or Last Updated |
2 Bytes |
Date, Created or Last Updated |
2 Bytes |
Starting Cluster |
4 Bytes |
File Size |
我们通过从根目录读取文件的信息恢复数据,然后将文件整合到目标路径并恢复文件。我们的下一个程序执行以下步骤来恢复数据:
- 读取根目录条目并在屏幕上显示它们以及所有信息,例如文件/目录名称、文件扩展名、文件的起始簇大小(以字节为单位)。
- 阅读子目录中的文件和目录信息,并在需要时显示它们。
- 确认要恢复的文件名并继续恢复。
- 计算要恢复的指定文件的 CHS(气缸、头部和扇区)信息。
- 从磁盘的数据区整合文件的数据,将恢复的文件保存到指定路径下的指定目标文件名。
本程序不关心软盘的引导信息是否可读。因此,您也可以从损坏的软盘中恢复甚至删除的数据。让我们看一下程序的编码:
/* 通过从根目录读取文件信息从软盘恢复数据的程序 */
#include<stdio.h>
#include<bios.h>
#include<dos.h>
void main()
{
void Display_Information(unsigned int,unsigned int,
unsigned int);
unsigned int track=0,head=1,sector=2;
Display_Information(track,head,sector);
} /*End of main */
void Display_Information(unsigned int track,
unsigned int head,
unsigned int sector)
{
void recover(unsigned int *,unsigned int);
char buf[512]; // Buffer of 512 Bytes
char ch;
struct diskinfo_t finfo; //Structure, Used by _bios_disk
unsigned int result,i,j, count=0; /* Unsigned Integers
Defined */
unsigned int file_no; /* Unsigned Integer
for File Number */
struct
{
unsigned int name[8],ext[3]; /* File Name for DOS in 8.3
(Eight Dot Three) Format */
unsigned int attribute; // File/Directory Attribute
unsigned int start; // Starting Cluster of the File
long unsigned int size; // Size of the File in Bytes
}root[32]; /* 32 Bytes Information of
File/Directory in Root
Directory */
clrscr();
do
{
file_no=0;
finfo.drive = 0x00; /* drive number for A: */
finfo.head = head; /* disk head number */
finfo.track = track; /* track number */
finfo.sector= sector; /* sector number */
finfo.nsectors=1; /* sector count */
finfo.buffer = buf; /* data buffer */
result = _bios_disk(_DISK_READ, &finfo); /* Read the
Sector */
if( (result & 0xff00) != 0) /* If Read Error, Display
Error Message and Exit*/
{
printf("Read error");
getch();
exit(0); // Go Back to DOS
}
/// 信息显示画面格式 \\\
clrscr();
gotoxy(9,1);
cprintf("DISPLAY CYLN: %u, HEAD: %u, SECTOR: %u",
track, head, sector);
gotoxy(9,2);
cprintf("FNO NAME EXT ATTRIBUTE START SIZE");
gotoxy(7,3);
cprintf("--------------------------------------------");
/* 一次一个扇区。每个文件/目录条目占用 32 个字节 */
for(i=0;i<512;i+=32)
{
for(j=0;j<8;j++)
{
/// 查找文件/目录名称 \\\
root[file_no].name[j]=buf[j+i];
}
for(j=8;j<11;j++)
{
/// 查找扩展名 \\\
root[file_no].ext[j-8]=buf[i+j];
}
j=11;
root[file_no].attribute=buf[i+j]; /// Attribute
/// 启动集群 \\\
root[file_no].start=(0xff & buf[27+i])*16*16 + (0xff & buf[26+i]);
/// 计算大小 \\\
root[file_no].size =(long unsigned int)(0xff &
buf[31+i])*16*16*16*16*16*16*16*16;
root[file_no].size+=(long unsigned int)(0xff &
buf[30+i])*16*16*16*16;
root[file_no].size+=(long unsigned int)(0xff &
buf[29+i])*16*16;
root[file_no].size+=(long unsigned int)(0xff &
buf[28+i]);
if((root[file_no].start == 0) ||
(root[file_no].attribute == 15))
continue;
else
{
gotoxy(8,i/32+4);
cprintf("%2u",file_no); /* Display File
Number */
for(j=0;j<8;j++)
{
gotoxy(14+j,i/32+4);
cprintf("%c",root[file_no].name[j]); /* Display File
Name */
}
for(j=0;j<3;j++)
{
gotoxy(26+j,i/32+4);
cprintf("%c",root[file_no].ext[j]); /* Display
Extension */
}
gotoxy(30,i/32+4);
cprintf("%u",root[file_no].attribute); /* Display
Attribute */
if(root[file_no].attribute==16)
{
gotoxy(33,i/32+4);
cprintf("<DIR>"); /* Display if Directory Attribute */
}
else
{
gotoxy(33,i/32+4);
cprintf("<FILE>"); /* The Entry is of a file */
}
gotoxy(44,i/32+4);
cprintf("%-5u", root[file_no].start); /* Display
Starting Cluster */
gotoxy(58,i/32+4);
cprintf("%-10lu", root[file_no].size); /* size of the
File */
}
file_no++;
}
gotoxy(10,
cprintf("Press 'M' : To see list of more files &quo
gotoxy(10,
cprintf("Press 'R' :To recover a file from the above
list&quo
ch=getc
请记住,以s开头的文件名(E5H)表示该文件已被删除,因此文件名的第一个字符已替换为s(参见前面章节中的根目录描述).
程序的输出显示如下:
DISPLAY CYLN: 0, HEAD: 1, SECTOR: 2
FNO NAME EXT ATTRIBUTE START SIZE
--------------------------------------------------------------------------
0 WE 32 <FILE> 15 1800
1 s2_INFO C 32 <FILE> 5 4700
2 THELP CFG 32 <FILE> 2 22
3 THELP COM 32 <FILE> 3 11072
4 TIMEIT CPP 32 <FILE> 39 1186
5 TOUCH COM 32 <FILE> 42 5124
6 TRY1 CPP 32 <FILE> 53 1581
7 TURBOC CFG 32 <FILE> 57 30
8 AA CPP 32 <FILE> 58 260
9 ABC CPP 32 <FILE> 59 1036
10 ASSIGN1 CPP 32 <FILE> 62 4257
11 CH24_2 CPP 32 <FILE> 71 834
12 sBSDISK1 C 32 <FILE> 73 911
13 sH24_25 C 32 <FILE> 75 594
14 sBSDISK C 32 <FILE> 77 840
Press 'M' : To see list of more files
Press 'R' :To recover a file from the above list R
|
DISPLAY CYLN: 0, HEAD: 1, SECTOR: 2
FNO NAME EXT ATTRIBUTE START SIZE
----------------------------------------------------------------------------
0 WE 32 <FILE> 15 1800
1 s2_INFO C 32 <FILE> 5 4700
2 THELP CFG 32 <FILE> 2 22
3 THELP COM 32 <FILE> 3 11072
4 TIMEIT CPP 32 <FILE> 39 1186
5 TOUCH COM 32 <FILE> 42 5124
6 TRY1 CPP 32 <FILE> 53 1581
7 TURBOC CFG 32 <FILE> 57 30
8 AA CPP 32 <FILE> 58 260
9 ABC CPP 32 <FILE> 59 1036
10 ASSIGN1 CPP 32 <FILE> 62 4257
11 CH24_2 CPP 32 <FILE> 71 834
12 sBSDISK1 C 32 <FILE> 73 911
13 sH24_25 C 32 <FILE> 75 594
14 sBSDISK C 32 <FILE> 77 840
Enter FNO. of the file you want to recover 1
You want to recover _2_INFO .C
Cylinder = 1, Head = 0, Sector = 1 Integrating........
Enter Path and Filename to recover the file: c:\windows\desktop\H2_INFO.C
Recovery Done !!!
|
编码评论:
Display_Information功能是从根目录读取文件和目录信息。在结构中,我们使用 root[32] 读取每个文件或目录的 32 字节信息。
无符号整数数组 name[8] 和 ext[3] 用于 8.3(八点三)格式的 DOS 文件或目录名称。类似地,一个字节用于属性,两个字节用于启动集群。长无符号整数大小;就是存储文件大小为四个字节。
_bios_disk函数读取结构体finfo指定的扇区,并将操作状态存储在result中。
从_bios_disk函数读取的每条512字节的信息,到根目录区结束,我们收集磁盘中存储的文件和目录的信息并将它们显示在屏幕上。
整数file_no是存储列表中文件或目录的编号,从0开始。一般根目录的大小为14个扇区,根目录一般从Cylinder =0, Head = 0, Sector =2开始在 1.44MB 和 3½ 的情况下;软盘。
如果用户给出字符 ‘M’或‘m’作为输入,如果用户选择的是“R”,则显示下一个扇区的信息。或‘r’调用恢复函数。 recover() 函数的编码如下:
/* 启动指定文件恢复的功能 */
void recover(unsigned int *root,unsigned int len)
{
void clear_the_line(unsigned int r); /* Function to Clear a Row on the Screen */
/* 整合指定文件的功能 */
void integrate(long unsigned int,unsigned int,
unsigned int,unsigned int);
unsigned int file_no,i;
char ch;
unsigned int *loc;
unsigned int cylinder,head,sector;
unsigned int start;
long unsigned int size;
clear_the_line(21); /* Clear The Row Number 21 */
clear_the_line(22); /* Clear The Row Number 22 */
clear_the_line(23); /* Clear The Row Number 23 */
clear_the_line(24); /* Clear The Row Number 24 */
gotoxy(10,21);
cprintf("Enter FNO. of the file you want to recover");
scanf("%u",&file_no); /* Get the File No. to be
Recovered */
loc=(root+(len*file_no/2));
/* 确认要恢复的文件名 */
gotoxy(10,22);
cprintf("You want to recover");
for(i=0;i<8;i++)
{
gotoxy(30+i,22);
cprintf("%c",*(loc+i)); /* File name */
}
gotoxy(38,22);
cprintf(".");
for(i=0;i<3;i++)
{
gotoxy(39+i,22);
cprintf("%c",*(loc+8+i)); /* File Extension */
}
start=*(loc+12);
/// 抱歉,您选择了目录 \\\
if(*(loc+11)==16)
{
gotoxy(5,23);
cprintf("Is A directory. Do you want to see the
contents of this directory Y/N");
ch=getch();
if(ch==27)
main();
if(ch=='y' || ch=='Y')
{
/* 计算几何 */
calculate(start,&cylinder,&head,§or);
/* 显示目录内容 */
Display_Information (cylinder,head,sector);
}
else
/* Ask for A file again and Continue Recovery */
recover(root,len);
}
else
{
size=*(loc+13);
/* 计算 CHS 信息 */
calculate(start,&cylinder,&head,§or);
/* 整合文件 */
integrate(size,cylinder,head,sector);
}
}
编码评论:
recover() 函数是获取用户输入以启动恢复。用户为恢复文件而输入的文件号,存储在file_no中。
如果输入的数字是目录条目,Display_Information() 会显示该目录的内容,否则屏幕上会显示文件编号 file_no 的文件名和扩展名,以确认要恢复的文件。
为了恢复指定文件,函数内调用函数calculate()和integrate()。函数calculate()的编码如下:
/* 计算恢复的 CHS 几何的功能 */
void calculate(unsigned int start,unsigned int *cylinder,
unsigned int *head,unsigned int *sector)
{
unsigned int temp;
*cylinder=0;
*head=1;
*sector=14;
if(start<5)
*sector=14+start;
else
{
temp= (start-4)/18;
if(temp>0)
{
if(temp%2==0)
*head=0;
else
*head=1;
*cylinder+=1+temp/2;
}
else
{
*head=0;
*cylinder=1;
}
*sector=(start-4)%18;
}
/// 显示要恢复的文件的 CHS \\\
gotoxy(10,23);
cprintf("Cylinder = %u, Head = %u, Sector = %u",
*cylinder,*head,*sector);
}
编码评论:
函数calculate()是为要恢复的文件计算Cylinder,Head和Sector信息。计算完成后,Cylinder、Head 和 Sector 的数字会显示在屏幕上。
函数integrate()的编码如下:
/* 整合文件并将恢复的文件保存到指定的路径和文件名 */
void integrate(long unsigned int size,
unsigned int cylinder,
unsigned int head,
unsigned int sector)
{
void clear_the_line(unsigned int);
/* 验证扇区是否有错误的功能 */
int verify_the_sector(unsigned int, unsigned int,
unsigned int);
int status;
char buf[512],*Filename_with_path;
struct diskinfo_t dinfo;
unsigned int result;
FILE *fp;
unsigned int left,i;
unsigned int sec;
/* 输入目标路径和文件名以保存恢复的文件 */
gotoxy(2,24);
cprintf("Enter Path and Filename to recover the file: ");
fflush(stdin);
gets(Filename_with_path);
fp=fopen(Filename_with_path,"wb");
/* 如果发生错误显示错误消息并再次获取输入路径和文件名 */
if(fp==NULL)
{
gotoxy(5,25);
cprintf("Error in opening the file");
getch();
clear_the_line(24);
gotoxy(0,25);
cprintf(" ");
integrate(size,cylinder,head,sector); /* Enter the
Destination Again */
}
/* 如果一切正常,集成并编写 */
gotoxy(50,23);
cprintf("Integrating........");
left= size%512;
sec = size/512;
sec++;
while(sec>0)
{
dinfo.drive = 0x00; /* drive number for A: */
dinfo.head = head; /* disk head number */
dinfo.track = cylinder; /* track number */
dinfo.sector= sector; /* sector number */
dinfo.nsectors=1; /* sector count */
dinfo.buffer = buf; /* data buffer */
result = _bios_disk(_DISK_READ, &dinfo);
/* If there is Error While Reading any Sector */
if( (result & 0xff00) != 0)
{
gotoxy(5,25);
cprintf("read error Cylinder %u, Head %u, Sector %u",
cylinder, head, sector);
}
else
{
if(sec==1)
{
for(i=0;i<left;i++)
fputc(buf[i],fp); /* Write The Integrated
Information to the File */
}
else
{
fwrite(buf,512,1,fp);
}
编码评论:
integrate()函数是执行恢复用户指定文件的实际模块,在这个恢复程序中。
文件名和存储恢复文件的目标路径存储在字符指针*Filename_with_path中。如果打开目标文件有任何错误,则会显示错误消息并再次提示用户输入目标。
函数_bios_disk(_DISK_READ, &dinfo); 从磁盘的数据区逐扇区读取文件的数据,由结构体dinfo指定,存放在数据缓冲区buf中.这个 512 字节的数据被写入目标文件。重复此过程,直到集成完整的文件。
函数status=verify_the_sector(柱面、磁头、扇区);验证要读取的扇区。如果状态 = 10,则表示坏 (0xA) 扇区。该函数的编码如下:
/// 验证扇区。 (此处不传输数据) \\\
int verify_the_sector(unsigned int c,unsigned int h,unsigned int s)
{
int status;
char *buf;
union REGS in, out;
struct SREGS sg;
in.h.ah = 0x04; /* Function Number */
in.h.al = 1; /* Number of Sectors to Verify*/
in.h.dl = 0x00; /* Drive Number for A: */
in.h.ch = c; /* Cylinder Number */
in.h.dh = h; /* Head Number */
in.h.cl = s; /* Sector Number */
in.x.bx = FP_OFF(buf);/* Offset */
sg.es = FP_SEG(buf); /* Segment */
int86x(0x13,&in,&out,&sg); /* Call the Function 4H
of INT 13H */
if(out.x.cflag)
{
status=out.h.ah;
}
return(status);
}
对编码的评论:
函数verify_the_sector(),验证_bios_disk()函数要读取的扇区,并返回操作状态。该函数使用 INT 13H 和函数 4H 来验证扇区。
*buf为数据缓冲区,0x04为in.h.ah指定的函数号=0x04;和 in.h.al = 1;指示一次验证一个扇区。 in.h.dl = 0x00;用于软盘驱动器 A 的驱动器编号:、c、h 和 s 是 Cylinder、Head 和 Sector 编号。
函数int86x()用于调用具有段寄存器值的INT 13H(函数4H)。操作的状态以整数状态返回。
函数clear_the_line() 清除屏幕上的指定行。函数编码如下:
/* 清除屏幕上的行,指定行号的功能 */
void clear_the_line(unsigned int row)
{
unsigned int column;
/* There are 80 Columns in a Row (Line) */
for(column=1;column<=80;column++)
{
gotoxy(column,row);
cprintf(" "); /* Clear With " " */
}
}
编码评论:
该函数用于清除屏幕上的指定行。使用要从屏幕上清除的行数调用该函数。