摘要:本文介绍了有关DOS磁盘系统严重错误的知识,并就如何屏蔽DOS磁盘系统严重错误的问题进行了较深入的探讨
关键词:DOS磁盘系统严重错误、中断向量、中断修改、磁盘检测(Disk Verifying)
在C语言程序设计时,程序员可能会碰到这样的尴尬场面:自己精心设计的用户界面被“Not ready reading drive A”之类的DOS磁盘错误提示所破坏,这是灾难性的。当程序员用fopen函数去操作A盘上的文件时,这种问题就可能会出现。为了讨论的方便,我们姑且将磁盘系统严重错误分为三种:磁盘检测错误(如扇区未找到、磁盘未准备、写保护错误等)、一般性硬件错误(如提示“General fail in drive A”等)和磁盘软件错误(如文件不存在等)。只要解决了这三个问题,那么本文的主要问题就解决了。
1、 磁盘检测错误
BIOS系统提供的13H号中断调用中04H子功能是扇区检测功能(Verify disk sector),调用这个磁盘检测功能可以取得一些磁盘的状态,如磁盘是否准备就绪等。本功能的返回参数如下:①如果成功,进位标志清零,AH=0,AL=检测的扇区数;②如果失败,进位标志置位,AH=错误代码。在磁盘系统中,换盘也被认为是一个错误,但对于用户来说,换盘操作是允许的,所以,这个功能应至少被调用三次,再判断返回参数,以确保正确性。
磁盘扇区检测功能虽然能够检测磁盘的一些硬件错误诸如“扇区未找到”、“磁盘未准备”等,但还有些错误却被忽视,比如磁盘的写保护错误。为此,我们只能够通过磁盘的物理扇区写操作来判断磁盘或驱动器的状态,方法是:先读出一个扇区(读三次)再用13H的03H功能将扇区写回(写三次),最后判断03H功能的返回参数(返回参数格式与04H相同)。如下的程序实现了这个功能,如果成果,返回0,如果失败,返回错误代码。
void IoSector (unsigned drive,unsigned action,
int head,int sector,int cylinder,
unsigned char *buffer)
{
regs.h.ah=action; regs.h.al=1;
regs.h.ch=cylinder; regs.h.cl=sector;
regs.h.dh=head; regs.h.dl=drive;
regs.x.bx=FP_OFF(buffer); sregs.es=FP_SEG(buffer);
int86x(0x13,®s,®s,&sregs);
}
int CheckSector (unsigned drive, unsigned head, unsigned sector, unsigned
cylinder)
{
int i;
unsigned char temp[512];
for (i=0;i<3;i++) IoSector (drive,0x02,0,1,0,temp);
for (i=0;i<3;i++)
{
regs.h.ah=3;
regs.h.al=1;
regs.x.bx=FP_OFF(temp);
sregs.es=FP_SEG(temp);
regs.h.ch=cylinder;
regs.h.cl=sector;
regs.h.dh=head;
regs.h.dl=drive;
int86x(0x13,®s,®s,&sregs);
}
if (regs.x.cflag)
return regs.h.ah;
else
return 0;
}
例如可以用err=CheckSector (0,0,1,0);方法得到err的值,进而判断A盘或驱动器的状态。
请读者注意:您也可以利用BIOS的13H号功能,01号子功能实现磁盘的状态测试,那样会更加简单方便。如果有兴趣的话,您可以按照上面的方法自己写一个磁盘状态测试函数。
附:入口参数:AH=01H, DL=drive (bit 7 set for Hard Disk)
出口参数:CF clear if successful (Return value = 0), set for error
AH=Status of previous operation. (See Appendex)
2、一般性硬件错误
要解决这些错误,只能修改中断向量。DOS的24H号中断是严重错误中断,当错误发生时中断激活。这个中断程序很特殊,它不需要程序员在退出程序时恢复对24H号中断的定义,这些事情DOS自己会去处理。程序员可以在24H号中断程序中仅仅设置一个标志来表示“错误发生”这一事件,最后在主程序中再通过这一标志去判断是否发生过这类错误。这一操作的实现代码如下:
#include <dos.h>
#ifdef __cplusplus
#define __ARGUMENT ...
#else
#define __ARGUMENT
#endif
int globalErr = 0;
void interrupt new24 (__ARGUMENT)
{
globalErr = 1;
}
void install (void interrupt (*fadd)(__ARGUMENT), int num)
{
disable();
setvect(num,fadd);
enable();
}
void main()
{
install (new24,0x24);
}
3、磁盘软件错误
这类错误最容易解决,只要在打开文件失败后将错误标志置位即可。
在C语言程序设计的过程中,结合上述的三种方法就能够屏蔽DOS磁盘系统的严重错误,使得在错误出现的时候不至于会破坏用户界面。在本文的最后是一个完整的测试程序,有兴趣的读者不妨上机调试一下,相信它对您帮助是非常大的。
#include <dos.h>
#include <conio.h>
#include <stdio.h>
#define COLOR(x,y) textcolor(x);textbackground(y)
#define LOCATE(x,y) gotoxy(x,y)
#ifdef __cplusplus
#define __ARGUMENT ...
#else
#define __ARGUMENT
#endif
int globalErr=0;
union REGS regs;
struct SREGS sregs;
void interrupt new24(__ARGUMENT)
{
globalErr=1;
}
void install(void interrupt (*fadd)(__ARGUMENT), int num)
{
disable();
setvect(num,fadd);
enable();
}
void IoSector (unsigned drive,unsigned action,
int head,int sector,int cylinder,
unsigned char *buffer)
{
regs.h.ah=action; regs.h.al=1;
regs.h.ch=cylinder; regs.h.cl=sector;
regs.h.dh=head; regs.h.dl=drive;
regs.x.bx=FP_OFF(buffer); sregs.es=FP_SEG(buffer);
int86x(0x13,®s,®s,&sregs);
}
int CheckSector (unsigned drive, unsigned head, unsigned sector, unsigned
cylinder)
{
int i;
unsigned char temp[512];
for (i=0;i<3;i++) IoSector (drive,0x02,0,1,0,temp);
for (i=0;i<3;i++)
{
regs.h.ah=3;
regs.h.al=1;
regs.x.bx=FP_OFF(temp);
sregs.es=FP_SEG(temp);
regs.h.ch=cylinder;
regs.h.cl=sector;
regs.h.dh=head;
regs.h.dl=drive;
int86x(0x13,®s,®s,&sregs);
}
if (regs.x.cflag)
return regs.h.ah;
else
return 0;
}
void main()
{
FILE *fp;
int verifyErr=0, fpointErr=0;
install(new24,0x24);
COLOR (15,1);
clrscr();
verifyErr=CheckSector(0,0,1,0);
if ((fp=fopen("a:\\abc.txt","rb"))==NULL) fpointErr=1;
if (globalErr)
{
LOCATE(10,10);
cprintf ("Hardware Error!");
goto handle;
}
if (verifyErr)
{
LOCATE(10,10);
cprintf ("Disk Error: Code %XH",verifyErr);
goto handle;
}
if (fpointErr)
{
LOCATE(10,10);
cprintf ("Unable to seek file!");
goto handle;
}
printf (“%XH\n”,fgetc(fp));
handle:
fclose(fp);
getch();
}
附录:磁盘操作状态参考
00h successful completion
01h invalid function in AH or invalid parameter
02h address mark not found
03h disk write-protected
04h sector not found/read error
05h reset failed (hard disk)
05h data did not verify correctly (TI Professional PC)
06h disk changed (floppy)
07h drive parameter activity failed (hard disk)
08h DMA overrun
09h data boundary error (attempted DMA across 64K boundary or >80h sectors)
0Ah bad sector detected (hard disk)
0Bh bad track detected (hard disk)
0Ch unsupported track or invalid media
0Dh invalid number of sectors on format (PS/2 hard disk)
0Eh control data address mark detected (hard disk)
0Fh DMA arbitration level out of range (hard disk)
10h uncorrectable CRC or ECC error on read
11h data ECC corrected (hard disk)
20h controller failure
31h no media in drive (IBM/MS INT 13 extensions)
32h incorrect drive type stored in CMOS (Compaq)
40h seek failed
80h timeout (not ready)
AAh drive not ready (hard disk)
B0h volume not locked in drive (INT 13 extensions)
B1h volume locked in drive (INT 13 extensions)
B2h volume not removable (INT 13 extensions)
B3h volume in use (INT 13 extensions)
B4h lock count exceeded (INT 13 extensions)
B5h valid eject request failed (INT 13 extensions)
BBh undefined error (hard disk)
CCh write fault (hard disk)
E0h status register error (hard disk)
FFh sense operation failed (hard disk)