第 10 章
从损坏的磁盘恢复数据
从损坏的软盘恢复数据
软盘是最不可靠的数据存储来源之一。如果您去任何使用计算机系统的组织并向其员工询问软盘引起的问题,您经常会听到这样的情况:问题是该组织的一名员工在他的软盘上保存了一些重要数据,而现在计算机无法读取软盘,并且屏幕上会出现类似如下的消息:
“无法读取光盘”
“坏道 0”
“无效光盘或容量”
“磁盘未格式化。您想现在格式化它吗?
对于使用计算机系统和软盘的组织来说,这是一个日常问题。当您发现没有对损坏的软盘上丢失的数据进行备份或没有可用的备份时,问题就变得很严重了。
最大的问题发生在当您将关键信息备份到软盘、恢复防病毒程序磁盘以克服病毒攻击、或将引导记录或其他备份(可能有多个选项)备份到软盘时,当您想要重新使用软盘中的备份时,会发生读取错误。
在这种情况下,您可能会丢失重要的信息和数据,并且在某些情况下,当您感到计算机的启动信息缺少备份和恢复程序、病毒攻击救援程序等时,由于软盘上存储的信息不足,计算机暂时无法读取这些信息,您可能会以操作系统故障的形式遭受重大数据丢失。
在这种情况下,最重要的要求就是从计算机系统识别为有故障的软盘中恢复数据。
软盘为何无法读取?
导致软盘出现此类错误信息的最常见问题是软盘的 DOS 引导记录 (DBR) 损坏,该记录可帮助计算机了解软盘的逻辑标识。
DBR 是存储在 0 磁道、0 磁头和 1 扇区的一小段程序,其中包含有关软盘的重要信息,例如:
- 每扇区的字节数
- 每簇扇区数
- FAT 数量
- 最大根目录数量等
由于软盘没有逻辑分区系统,所以软盘上没有MBR。软盘的第一个扇区包含 DBR。这也是硬盘与软盘逻辑结构比较的主要区别。
当我们使用任何磁盘编辑程序读取软盘的引导扇区信息时,它将显示如下图所示的信息。
下图显示了 1.44 MB、3.5 英寸软盘上的 512 字节 DBR 信息。

如果这些信息因某种原因损坏或无法读取,软盘就会产生这些读取错误消息。这可能是由于磁盘第一个扇区的物理或逻辑损坏造成的。
逻辑损坏包括软盘第一个扇区中的信息发生更改、某个扇区逻辑上损坏或软盘的DBR由于其他原因损坏的情况。
如果软盘的第一个扇区出现物理坏扇区(即扇区 1 受到物理损坏),则认为发生了物理损坏。当您发现软盘的第 0 磁道上有多个坏扇区时,问题就变得更加严重了。
如何恢复
既然我们已经了解了造成损坏的两个原因,我希望您现在可以理解这个问题了。从逻辑损坏中恢复数据并不困难,但从物理损坏中恢复则需要付出更多努力。
方法 – 1
保存任何新软盘的可启动映像。
如果问题合乎逻辑,现在我们明白如何恢复数据了。我们需要做的只是从另一张大小和容量相同的软盘中获取适当的引导记录,并将其粘贴到无法读取的软盘的第一个扇区。虽然问题是由于引导记录错误造成的,但现在应该可以正常工作了。
此过程涉及两个步骤,我们可以按照这些步骤从无法读取的软盘中恢复数据:
- 制作一张好的软盘的 DOS 引导记录映像
- 将启动映像粘贴到无法读取的软盘的第一个扇区
制作一张好的软盘的 DOS 引导记录映像
为了存储新软盘的引导记录映像,程序必须执行以下三个任务:
- 准确读取好软盘的前 512 个字节
- 检查读取操作是否成功(最重要的)
- 将这 512 个字节存储到指定的文件名和目标路径
软盘的扇区为 512 字节,因此需要复制该扇区的准确映像。在软盘上执行任何类型的操作时,检查操作是否成功都是最重要且必要的步骤。
即使是好的、全新的软盘也可能存在初始化问题。这就是为什么在大多数情况下,当对软盘进行操作时,首先在编程中使用重置磁盘操作(INT 13H 的功能 00 H)对软盘进行初始化。
如果初始化后最近插入的软盘或更换的软盘仍然导致读取错误,建议您再次运行该程序,很可能这次它可以正常工作。
以下程序将执行这些指定的任务。让我们看看它是如何进行的:
/*将启动映像从新软盘存储到文件中*/
#包括 <bios.h>
#包括 <stdio.h>
int main(空)
{
结构diskinfo_t dinfo;
工会 REGS 法规;
int 结果;
int 计数=0,i;
char fname[80];
静态字符 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”);
如果((fp = fopen(fname,“wb”))==NULL)
{
高视频();
gotoxy(10,10);cprintf("无法创建文件");
获取();
退出(0);
}
乙氧基(10,9);
cprintf("尝试从软盘驱动器读取:\n");
///初始化磁盘系统\\\
对于(i = 0;i <3;i ++)
{
regs.h.ah = 0x00; /* 重置磁盘系统 */
regs.h.dl = 0x00; /* 软盘 a: */
int86(0x13,&regs,&regs);
}
结果 = _bios_disk(_DISK_READ,&dinfo);
如果 ((结果 & 0xff00) == 0)
{
while(计数<512)
{
fprintf(fp,"%c",dbuf[count] & 0xff );
计数++;
}
fclose(fp);
gotoxy(10,14);cprintf("从软盘驱动器读取磁盘
:成功。\n”);
}
别的
{
乙氧基(10,14);
cprintf("无法读取驱动器 A,状态 = 0x%02x\n", result);
切换(结果)
{
情况 0x00:
cprintf("\n\n状态:无错误!! ");
休息;
案例 0x01:
cprintf("\n\n 状态:错误命令");
休息;
案例 0x02:
cprintf("\n\n STATUS:未找到地址标记");
休息;
案例 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 STATUS:搜索操作失败");
休息;
案例 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 STATUS:有效弹出请求失败 (INT 13H 扩展) ");
休息;
默认值:cprintf(“\n\n状态:软盘错误的未知状态代码”);
}
}
返回0;
}
程序编码注释:
在前面给出的程序编码中,基本上我们正在逐步执行以下任务:
- dinfo 指向 diskinfo_t 结构,该结构包含 _bios_disk 函数执行操作所需的参数信息。
- 由于我们要读取磁盘的第一个扇区,因此该扇区的位置如下:
范围 |
含义 |
dinfo.驱动器 = 0x00 |
它表示驱动器0是软盘驱动器 ( a: ) |
dinfo.head = 0 |
它指向0号头 |
dinfo.track = 0 |
它指向0 号轨道 |
dinfo.扇区 = 1 |
软盘的第一个扇区,即扇区1 |
dinfo.扇区 = 1 |
读取操作要考虑的扇区数 = 1 |
dinfo.buffer = 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) 读取软盘的指定扇区。
- 返回的状态存储在结果中,用于显示操作成功的消息或如果发生任何错误则在屏幕上显示错误消息。

将启动映像粘贴到无法读取的软盘的第一个扇区
为了将文件中的启动映像粘贴到无法读取的软盘的第一个扇区,我们必须在程序中执行以下三个主要任务:
- 从先前保存的文件中读取新软盘引导记录的精确 512 字节信息。
- 将此信息写入软盘的第一个扇区,该扇区当前不可读。
- 检查写入操作是否成功完成(最重要的)。
由于软盘扇区为 512 字节,因此需要将准确的启动映像粘贴到该扇区。在软盘上执行任何类型的操作时,检查操作是否成功是最重要且必要的步骤。
操作过程中软盘可能存在初始化问题,因此必须通过重置磁盘系统(使用 INT 13H 的功能 00H)来初始化磁盘。
如果初始化后最近插入的软盘或更换的软盘仍然导致读取错误,建议您再次运行该程序,很可能这次它可以正常工作。
以下程序将执行这些指定的任务。让我们看看它是如何进行的:
/*将启动映像加载到不可读的软盘*/
#包括 <bios.h>
#包括 <stdio.h>
int main(空)
{
结构diskinfo_t dinfo;
工会 REGS 法规;
int 结果;
int 计数=0,i;
char fname[80];
char dbuf[512];
文件*fp;
clrscr();
gotoxy(5,3);cprintf("请输入存储软盘启动映像的文件名和路径");
乙氧基(5,5);
获取(fname);
fp=fopen(fname,“rb”);
如果((fp = fopen(fname,“rb”))==NULL)
{
高视频();
gotoxy(10,10);cprintf("无法打开文件");
获取();
退出(0);
}
乙氧基(10,9);
cprintf("正在尝试恢复软盘驱动器:\n");
///初始化磁盘系统\\\
对于(i = 0;i <3;i ++)
{
regs.h.ah = 0x00; /* 重置磁盘系统 */
regs.h.dl = 0x00; /* 软盘 a: */
int86(0x13,&regs,&regs);
}
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)
{
fclose(fp);
gotoxy(10,14);cprintf("成功!!!我希望 Floppy 可能
现在工作。\n");
}
别的
{
乙氧基(10,14);
cprintf("无法读取驱动器 A,状态 = 0x%02x\n",result);
乙氧基(10,16);
切换(结果)
{
情况 0x00:
cprintf("\n\n状态:无错误!! ");
休息;
案例 0x01:
cprintf("\n\n 状态:错误命令");
休息;
案例 0x02:
cprintf("\n\n STATUS:未找到地址标记");
休息;
案例 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 STATUS:搜索操作失败");
休息;
案例 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 STATUS:有效弹出请求失败 (INT 13H 扩展) ");
休息;
默认值:cprintf(“\n\n状态:软盘错误的未知状态代码”);
}
}
返回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) 将指定文件中的启动信息写入软盘的第一个(指定)扇区。
- 返回的状态存储在结果中,用于显示操作成功的消息或如果发生任何错误则在屏幕上显示错误消息。
范围 |
含义 |
dinfo.驱动器 = 0x00 |
它表示驱动器0是软盘驱动器 ( a: ) |
dinfo.head = 0 |
它指向0号头 |
dinfo.track = 0 |
它指向0 号轨道 |
dinfo.扇区 = 1 |
软盘的第一个扇区,即扇区1 |
dinfo.扇区 = 1 |
写入操作需要考虑的扇区数 = 1 |
dinfo.buffer = dbuf |
操作的数据缓冲区 |
让我们用单个程序来完成
我希望现在您已经理解了这种从软盘恢复数据的概念。之后,让我们想象一个程序,它可以给出我们在前面讨论的两个程序的帮助下得到的相同结果。
我们正在使用最近讨论的程序执行以下任务:
- 将好软盘上的启动信息存储到文件中
- 将此信息粘贴到当前无法读取的软盘的第一个扇区我们用来存储启动映像的文件充当连接两个程序操作的中间桥梁。但如果我们在程序编码本身中定义此启动信息,我们就不需要创建文件,也不需要从文件中读取软盘的启动信息。
在我们的下一个程序中,我们告诉我们的程序它必须在不可读软盘的第一个扇区中写入什么,这样我们就可以避免两个不同的程序执行相同的任务,并且我们可以以与以前相同的方式从新的单个程序中恢复我们的数据。
因此,程序变得简单,代码量减少,并且我们能够降低文件读取、写入或创建错误发生的概率。我们在这个程序中执行以下四个重要任务:
看到dbuf[512]这512字节的16进制信息,不要以为程序很难写,很难理解,后面我们会讨论如何把这些信息轻松写入程序代码中。
- 定义以十六进制形式写入当前不可读软盘第一个扇区的 DOS 引导记录信息。
- 重置磁盘系统以初始化软盘(INT 13H,功能 00H)。
- 将 DOS 引导记录写入软盘的第一个扇区
- 检查操作是否成功完成以及是否发生错误。
让我们检查一下这个程序:
/*单个程序将默认启动映像加载到不可读的软盘*/
#包括 <bios.h>
#包括 <stdio.h>
int main(空)
{
结构diskinfo_t dinfo;
工会法规:
int 结果,i;
/*启动映像将被加载到软盘驱动器中*/
静态字符 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; /* 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,&regs,&regs);
}
结果 = _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 STATUS:未找到地址标记");
休息;
案例 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 STATUS:搜索操作失败");
休息;
案例 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 STATUS:有效弹出请求失败 (INT 13H 扩展) ");
休息;
默认值:cprintf(“\n\n状态:软盘错误的未知状态代码”);
}
}
返回0;
}
在这个程序编码中,基本上我们将逐步执行以下这些任务:
- 静态字符数据缓冲区dbuf[512]提供了512个十六进制字节的信息,这些信息将被写入不可读软盘的第一个扇区。dbuf[512]在操作过程中告诉计算机应该在软盘的第一个扇区中写入什么信息。(参见下一个程序)
- dinfo 指向 diskinfo_t 结构,该结构包含 _bios_disk 函数执行操作所需的参数信息。
- 由于我们要将信息写入磁盘的第一个扇区,因此该扇区的位置如下:
范围 |
含义 |
dinfo.驱动器 = 0x00 |
它表示驱动器0是软盘驱动器 ( a: ) |
dinfo.head = 0 |
它指向0号头 |
dinfo.track = 0 |
它指向0 号轨道 |
dinfo.扇区 = 1 |
软盘的第一个扇区,即扇区1 |
dinfo.扇区 = 1 |
写入操作需要考虑的扇区数 = 1 |
dinfo.buffer = 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) 将指定文件中的启动信息写入软盘的第一个(指定)扇区。
返回的状态存储在结果中,用于显示操作成功的消息或如果发生任何错误则在屏幕上显示错误消息。
将启动映像存储在十六进制字符中,以便在我们之前的程序中使用
在我们最近讨论的程序中,手动以十六进制系统无误地写入软盘 DOS 引导记录的所有 512 个字符将是一项非常困难的工作。即使我们能够准确地写入,这也是一项困难且耗时的任务。让我们使用一些巧妙的思路将数据缓冲区 dbuf[512] 的数据存储在一个文件中。
我们知道,在 C 语言中十六进制字符用 0x 表示,如果十六进制字符是 A9 H,则在 C 语言程序中应将其写为 0xA9。我们的下一个程序也是这样做的。它将存储我们在上一个程序中需要写入的数据,作为数据缓冲区 dbuf[512] 的数据。
您所要做的只是使用一张全新的软盘来制作其 DBR 的映像,并从指定的目标文件复制此程序的输出并将此数据粘贴到您的程序中。如果需要,请进行一些格式化。让我们看看它是如何工作的:
/*以十六进制字符制作软盘启动映像的程序*/
#包括 <bios.h>
#包括 <stdio.h>
int main(空)
{
结构diskinfo_t dinfo;
工会 REGS 法规;
int 结果,i;
int计数=0;
char fname[80];
静态字符 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”);
如果((fp = fopen(fname,“wb”))==NULL)
{
高视频();
gotoxy(10,10);cprintf("无法创建文件");
获取();
退出(0);
}
///初始化磁盘系统\\\
对于(i = 0;i <3;i ++)
{
regs.h.ah = 0x00; /* 重置磁盘系统 */
regs.h.dl = 0x00; /* 软盘 a: */
int86(0x13,&regs,&regs);
}
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 );
计数++;
}
fclose(fp);
}
别的
{
乙氧基(10,14);
cprintf("无法读取驱动器 A,状态 = 0x%02x\n",
结果);
}
返回0;
}
对程序编码的注释:
这样数据就存储在指定的文件中了。只需将数据复制到程序中并进行一些必要的格式化即可。在整个过程中,您永远不要忘记以下提示:
- 确保程序运行成功,并且存储在目标文件中的数据是适当的。
- 您应该彻底检查操作是否发生预期的错误。
- 在读取软盘的引导扇区之前,必须先用程序初始化软盘。为此,您可以使用 INT 13H 的 00H 功能。
方法 – 2
如果方法 1 不起作用该怎么办?
如果方法 1 不起作用,并且无法读取的磁盘不允许程序在其第一个扇区上重写引导信息,则应尝试第二种方法。第一种方法失败的原因可能是软盘第一个扇区的物理损坏。
在第二种方法中,我们将把无法读取的软盘表面的所有数据临时复制到一个文件中,然后将该图像直接粘贴在另一个好磁盘的表面上。
该程序涉及以下两个重要步骤:
- 逐个扇区地将软盘介质表面的所有数据临时复制到一个文件中。
- 将先前存储在文件中的数据粘贴到新的软盘的相同扇区中。
将媒体表面的所有数据复制到单个文件中
为了存储软盘介质表面的所有数据,程序必须执行以下三个任务:
- 借助INT 13H的00H功能正确初始化磁盘。
- 读取表面的逐个扇区信息并将其存储到单个文件中。
- 检查读取操作是否成功(最重要的)
软盘出现初始化问题很常见,这会导致许多读取失败的消息。这就是为什么在读写操作之前必须借助编程对磁盘进行初始化的原因。
当对软盘进行任何类型的操作时,检查操作是否成功是最重要且必要的步骤。
如果初始化后最近插入的软盘或更换的软盘仍然导致读取错误,建议您再次运行该程序,很可能这次它可以正常工作。
以下程序将执行这些指定的任务。让我们看看它是如何进行的:
/*将软盘物理表面的数据存储到文件中的程序*/
#包括 <bios.h>
#包括 <stdio.h>
无效主要(无效)
{
int 头部,轨道;
工会 REGS 法规;
int 结果,i,部门;
char 文件名[80];
结构diskinfo_t dinfo;
静态字符 dbuf[512];
文件*tt;
clrscr();
printf("\n 输入要存储的文件名和路径
数据暂时\n”);
获取(文件名);
如果((tt = fopen(文件名,“wb”))==NULL)
{
printf("无法创建文件,
按任意键退出”);
获取();
退出(0);
}
printf("\n 正在初始化软盘系统...\n");
///初始化磁盘系统\\\
对于(i = 0;i <3;i ++)
{
regs.h.ah = 0x00; /* 重置磁盘系统 */
regs.h.dl = 0x00; /* 软盘 a: */
int86(0x13,&regs,&regs);
}
对于(轨道=0;轨道<=79;轨道++)
{
对于(头部=0;头部<=1;头部++)
{
对于(扇区=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 指向 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的参数如下:
范围 |
含义 |
dinfo.驱动器 = 0x00 |
它表示驱动器0是软盘驱动器 ( a: ) |
dinfo.head =头部 |
它指向磁头编号0 和 1,因为软盘有两面(两个磁头) |
dinfo.track =轨迹 |
它指向0 至 79磁道,因为软盘每面有80 个磁道。 |
dinfo.sector =扇区 |
它指向1 至 18扇区,因为每个磁道有18 个扇区。 |
dinfo.扇区 = 1 |
读取操作要考虑的扇区数 = 1 |
dinfo.buffer = 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 引导记录。
让我们看看如何通过编程来实现它:
#包括 <bios.h>
#包括 <stdio.h>
无效主要(无效)
{
int 头部,轨道;
工会 REGS 法规;
int 结果,i,部门;
char 文件名[80];
结构diskinfo_t dinfo;
静态字符 dbuf[512];
/* 512字节的信息用于填充坏扇区的空间*/
///我使用 512 个零来填充 512 个字节的空间\\\
静态字符 dbuf2[512] =
“000000000000000000000000000000000” “000000000000000000000000000000000” “00000000000000000000000000000000” “000000000000000000000000000000000” “000000000000000000000000000000000” “00000000000000000000000000000000” “00000000000000000000000000000000” “000000000000000000000000000000000” “000000000000000000000000000000000” “00000000000000000000000000000000” “000000000000000000000000000000000” “000000000000000000000000000000000” “00000000000000000000000000000000” “00000000000000000000000000000000” “00000000000000000000000000000000”“00000000000000000000000000000000”;
文件*tt;
clrscr();
printf("\n 输入要存储的文件名和路径
数据暂时\n”);
获取(文件名);
如果((tt = fopen(文件名,“wb”))==NULL)
{
printf("无法创建文件,请按任意键
出口”);
获取();
退出(0);
}
printf("\n 正在初始化软盘系统...\n");
///初始化磁盘系统\\\
对于(i = 0;i <3;i ++)
{
regs.h.ah = 0x00; /* 重置磁盘系统 */
regs.h.dl = 0x00; /* 软盘 a: */
int86(0x13,&regs,&regs);
}
对于(轨道=0;轨道<=79;轨道++)
{
对于(头部=0;头部<=1;头部++)
{
对于(扇区=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",结果,磁头,磁道,扇区);
/*如果 Sector 不可读,则用 dbuf2 占用 512 字节*/
fwrite(dbuf2,512,1,tt);
}
printf("正在读取 磁道= %d 磁头= %d 扇区= %d\n",
磁道、磁头、扇区);
}
}
}
}
程序编码注释:
在程序的编码中,除了数据缓冲区 dbuf2[512] 之外,每个步骤都与上一个程序相同,我们使用它来处理磁盘读取操作期间由坏扇区产生的错误并维持映像文件的大小。
通过这样做,我们正在填充无法从坏扇区读取的信息的空间,现在我们正在写入 512 字节的伪信息,以便我们可以保持磁盘映像的准确性。
将文件中的数据粘贴到新软盘的物理表面:
在此步骤中,我们将上一个程序存储在文件中的数据逐个扇区地粘贴到新软盘的物理表面,方式与将其复制到文件的方式相同。
该计划的主要步骤如下:
- 打开我们临时存储无法读取的软盘的表面数据的文件。
- 通过INT 13H的复位功能00H正确初始化磁盘系统。
- 将文件中的信息写入新软盘的扇区上。
- 同时显示写入状态,以发现或避免错误的发生。
程序源代码如下。让我们来看看它是如何工作的:
/*程序将前一个程序创建的文件的数据写入新软盘表面的扇区*/
#包括 <bios.h>
#包括 <stdio.h>
无效主要(无效)
{
int 头部,轨道;
工会 REGS 法规;
int 结果,i,部门;
int 计数 =0;
char 文件名[80];
结构diskinfo_t dinfo;
静态字符 dbuf[512];
文件*fp;
clrscr();
printf("\n 输入要存储的文件名和路径
数据暂时\n”);
获取(文件名);
如果((fp = fopen(文件名,“rb”))==NULL)
{
printf("无法创建文件,请按任意键
出口”);
获取();
退出(1);
}
///初始化磁盘系统\\\
对于(i = 0;i <3;i ++)
{
regs.h.ah = 0x00; /* 重置磁盘系统 */
regs.h.dl = 0x00; /* 软盘 a: */
int86(0x13,&regs,&regs);
}
对于(轨道=0;轨道<=79;轨道++)
{
对于(头部=0;头部<=1;头部++)
{
对于(扇区=1;扇区<=18;扇区++)
{
计数=0;
while(计数<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 指向 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的参数如下:
范围 |
含义 |
dinfo.驱动器 = 0x00 |
它表示驱动器0是软盘驱动器 ( a: ) |
dinfo.head =头部 |
它指向磁头编号0 和 1,因为软盘有两面(两个磁头) |
dinfo.track =轨迹 |
它指向0 至 79磁道,因为软盘每面有80 个磁道。 |
dinfo.sector =扇区 |
它指向1 至 18扇区,因为每个磁道有18 个扇区。 |
dinfo.扇区 = 1 |
写入操作需要考虑的扇区数 = 1 |
dinfo.buffer = dbuf |
操作的数据缓冲区 |
- _bios_disk(_DISK_WRITE, &dinfo)将数据写入软盘物理表面的扇区,由 dinfo 指定。
- 返回的状态存储在结果中,用于显示操作成功的消息或如果发生任何错误则在屏幕上显示错误消息。
如果执行方法 2 后您的新软盘仍然无法工作,您可以进一步在新软盘上应用方法 1,该软盘在方法 2 中用作目标磁盘。
不仅如此,根据磁盘损坏程度,点击和尝试的次数也可能不同。但即使您没有得到满意的结果,也不必担心。
您可以尝试逐个文件恢复,也可以尝试更多技巧,这些技巧将在下文中介绍。在这里,我们将在编程中实现从根目录收集文件信息的想法,以恢复数据。
对已删除或丢失数据的逻辑恢复思考:
我们在本章中讨论的所有先前的恢复情况都是在以下情况下恢复数据:我们预计只有DBR 损坏并且轨道 0 中的扇区(具有 FAT1、FAT2 和根目录)可读。
但是,如果问题是由于 FAT 损坏或数据已从磁盘中删除,或者您想通过从根目录读取其信息来直接恢复数据,则我们需要从其根目录条目中读取文件名、起始簇、文件大小、属性等信息。
正如我们在前面章节中讨论过的根目录一样,每个文件或目录都有 32 个字节的信息。这 32 个字节的划分如下:
字节数 |
信息描述 |
8 字节 |
文件名 |
3 字节 |
扩大 |
1 字节 |
属性 |
10 字节 |
预订的 |
2 个字节 |
创建时间或上次更新时间 |
2 个字节 |
创建日期或上次更新日期 |
2 个字节 |
启动集群 |
4 字节 |
文件大小 |
我们通过从根目录读取文件信息来恢复数据,然后将文件集成到目标路径并恢复文件。我们的下一个程序执行以下步骤来恢复数据:
- 读取根目录条目并将其与所有信息(例如文件/目录名称、文件扩展名、文件的起始簇大小(以字节为单位))一起显示在屏幕上。
- 读取子目录中的文件和目录信息,并根据需要显示它们。
- 确认要恢复的文件名并继续恢复。
- 计算要恢复的指定文件的CHS(柱面、磁头和扇区)信息。
- 从磁盘的数据区整合文件的数据,并将恢复的文件保存到指定路径的指定目标文件名。
此程序不关心软盘的启动信息是否可读。因此,您也可以从损坏的软盘中恢复已删除的数据。让我们看看程序的代码:
/*通过从根目录读取文件信息来从软盘恢复数据的程序*/
#include<stdio.h>
#包括<bios.h>
#include<dos.h>
空主()
{
void Display_Information(无符号整数,无符号整数,
无符号整数);
无符号整数磁道=0,磁头=1,扇区=2;
显示信息(磁道,磁头,扇区);
} /*主要部分结束*/
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]; /* 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("读取错误");
获取();
exit(0); //返回DOS
}
///信息显示屏格式\\\
clrscr();
乙氧基(9,1);
cprintf("显示柱面数:%u,磁头数:%u,扇区数:%u",
磁道、磁头、扇区);
乙氧基(9,2);
cprintf("FNO 名称 EXT 属性 起始大小");
乙氧基(7,3);
cprintf(“-------------------------------------”);
/*每次一个扇区。每个文件/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 ++)
{
///查找扩展\\\
根[文件编号].ext[j-8]=buf[i+j];
}
j=11;
root[file_no].attribute=buf[i+j]; /// 属性
///启动集群\\\
根[文件编号].起始=(0xff & buf[27+i])*16*16 + (0xff & buf[26+i]);
///计算尺寸\\\
根[文件编号].大小 =(长无符号整数)(0xff &
buf[31+i])*16*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 &
缓冲区[28 + i]);
如果((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); /*显示
属性 */
如果(根[文件编号].属性==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函数用于从根目录读取文件和目录信息。在结构中,我们读取 root[32] 的每个文件或目录的 32 字节信息。
无符号整数数组 name[8] 和 ext[3] 表示 DOS 8.3(八点三)格式的文件或目录名称。同样,一个字节表示属性,两个字节表示起始簇。long unsigned int size; 用于存储四个字节的文件大小。
_bios_disk函数读取结构 finfo 指定的扇区,并将操作的状态存储在 result 中。
从_bios_disk函数读取的每一个512字节的信息开始,直到根目录区域结束,我们收集磁盘中存储的文件和目录的信息并显示在屏幕上。
整数 file_no 存储列表中文件或目录的编号,从 0 开始。对于 1.44MB 和 3½ 软盘,根目录的大小通常为 14 个扇区,并且根目录通常从 Cylinder =0、Head =0 和 Sector =2 开始。
如果用户输入字符“M”或“m”,则显示下一个扇区的信息;如果用户的选择是“R”或“r”,则调用恢复函数。函数recover()的代码如下所示:
/*启动指定文件恢复的函数*/
void 恢复(无符号整数 *root,无符号整数 len)
{
void clear_the_line(unsigned int r); /* 清除屏幕上一行的函数 */
/*函数整合指定文件*/
void 积分(长无符号整数,无符号整数,
无符号整数,无符号整数);
无符号整数文件编号,i;
字符 ch;
无符号整数*loc;
无符号整数柱面,磁头,扇区;
无符号整数开始;
长无符号整数大小;
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=(root+(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)
主要的();
如果 (ch=='y' || ch=='Y')
{
/*计算几何*/
计算(开始,&气缸,&头部,&扇区);
/*显示目录内容*/
显示信息(圆柱,磁头,扇区);
}
别的
/* 再次请求 A 文件并继续恢复 */
恢复(root,len);
}
别的
{
大小=*(loc+13);
/*计算 CHS 信息*/
计算(开始,&气缸,&头部,&扇区);
/*集成文件*/
整合(尺寸,圆柱,头部,扇区);
}
}
编码注释:
函数recover()用于获取用户输入以启动恢复。用户输入的用于恢复文件的文件编号存储在file_no中。
如果输入的数字是目录条目,Display_Information() 将显示该目录的内容,否则将在屏幕上显示文件编号 file_no 的文件名和扩展名,以确认要恢复的文件。
为了恢复指定的文件,在函数中调用了函数calculate()和integration()。函数 calculate() 的代码如下所示:
/*函数用于计算恢复的 CHS 几何体*/
void 计算(无符号整数开始,无符号整数*圆柱体,
无符号整数*head,无符号整数*sector)
{
无符号整数温度;
*圆柱体=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 整合(长无符号整数大小,
无符号整数圆柱体,
无符号整数头,
无符号整数扇区)
{
无效清除线(无符号整数);
/*用于验证扇区错误的函数*/
int verify_the_sector(无符号整数,无符号整数,
无符号整数);
int 状态;
char buf[512],*Filename_with_path;
结构diskinfo_t dinfo;
无符号整数结果;
文件*fp;
无符号整数左,i;
无符号整数 sec;
/*输入目标路径和文件名以保存恢复的文件*/
乙氧基(2,24);
cprintf("输入恢复文件的路径和文件名:");
fflush (标准输入);
获取(文件名和路径);
fp=fopen(Filename_with_path,“wb”);
/*如果发生错误则显示错误消息并再次获取输入路径和文件名*/
如果 (fp==NULL)
{
乙氧基(5,25);
cprintf("打开文件错误");
获取();
清除线(24);
乙氧基(0,25);
cprintf(“ “);
整合(尺寸,圆柱,头部,扇区);/*输入
再次前往目的地 */
}
/*如果一切正常,则集成并写入*/
乙氧基(50,23);
cprintf("正在集成........");
左=尺寸%512;
秒=大小/512;
秒++;
当(秒> 0)
{
dinfo.drive = 0x00; /* A 的驱动器号: */
dinfo.head = head; /* 磁盘头号 */
dinfo.track = cylinder; /* 轨道号 */
dinfo.sector= sector; /* 扇区号 */
dinfo.nsectors=1; /* 扇区数 */
dinfo.buffer = buf; /* 数据缓冲区 */
结果 = _bios_disk(_DISK_READ,&dinfo);
/* 如果读取任何扇区时出现错误 */
如果((结果 & 0xff00)!= 0)
{
乙氧基(5,25);
cprintf("读取错误柱面 %u、磁头 %u、扇区 %u",
柱面、磁头、扇区);
}
别的
{
如果(秒==1)
{
对于(i = 0; i <左; 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); 验证要读取的扇区。如果 status = 10,则表示扇区为坏扇区 (0xA)。该函数的编码如下所示:
///验证扇区。(此处未传输任何数据) \\\
int verify_the_sector(无符号整数 c、无符号整数 h、无符号整数 s)
{
int 状态;
字符 *buf;
联合 REGS 输入、输出;
结构 SREGS sg;
in.h.ah = 0x04; /* 功能编号 */
in.h.al = 1; /*要验证的扇区数*/
in.h.dl = 0x00; /* A 的磁盘编号: */
英寸.h.ch = c; /* 气缸编号 */
在.h.dh = h; /* 头号 */
在.h.cl = s; /* 扇区号 */
in.x.bx = FP_OFF(buf);/* 偏移量 */
sg.es = FP_SEG(缓冲区); /* 部分 */
int86x(0x13,&in,&out,&sg); /* 调用函数 4H
来自 INT 13H */
如果(out.x.cflag)
{
状态=out.h.ah;
}
返回(状态);
}
编码注释:
verify_the_sector() 函数验证将由 _bios_disk() 函数读取的扇区并返回操作的状态。该函数使用 INT 13H 和函数 4H 来检查扇区。
*buf — 数据缓冲区,0x04 — in.h.ah = 0x04 指定的功能编号;且吸入量 = 1;表示每次应检查一个扇区。 in.h.dl = 0x00;用于软盘驱动器号A:,c、h和s分别是磁柱面号、磁头号和扇区号。
int86x()函数用于使用段寄存器值调用 INT 13H(函数 4H) 。操作状态以整数状态返回。
clear_the_line()函数清除屏幕上的指定行。函数编码如下:
/*函数用于清除屏幕上指定行号的一行*/
void clear_the_line(无符号整数字符串)
{
无符号整数列;
/* 一行有 80 列 */
对于(列=1;列<=80;列++)
{
gotoxy(列,行);
cprintf(“ “); /* 用“ ”清除 */
}
}
编码注释:
该函数用于清除屏幕上的指定行。该函数使用需要从屏幕上清除的行号进行调用。