中国DOS联盟论坛

中国DOS联盟

-- 联合DOS 推动DOS 发展DOS --

联盟域名:www.cn-dos.net  论坛域名:www.cn-dos.net/forum
DOS,代表着自由开放与发展,我们努力起来,学习FreeDOS和Linux的自由开放与GNU精神,共同创造和发展美好的自由与GNU GPL世界吧!

游客:  注册 | 登录 | 命令行 | 会员 | 搜索 | 上传 | 帮助 »
中国DOS联盟论坛 » DOS开发编程 & 发展交流 (开发室) » 读取硬盘绝对扇区的函数(刚写的,纯DOS)
« [1] [2] »
作者:
标题: 读取硬盘绝对扇区的函数(刚写的,纯DOS) 上一主题 | 下一主题
GOTOmsdos
铂金会员

C++启程者


积分 5154
发帖 1827
注册 2003-7-18
状态 离线
『楼 主』:  读取硬盘绝对扇区的函数(刚写的,纯DOS)

(刚写的,有8.4G限制,谁有读取137G以上的函数,贴出来学习一下,据说是扩展13终端)

#include <bios.h>
#include <conio.h>
#include <stdio.h>

/*将读取的硬盘扇区以相应的扇区数为单位存到文件的函数(每次的读取数必须在65535字节内,否则无效)*/
void writeFile(unsigned char *buffer, unsigned int sector, char *filename)
{
FILE *f;

if((f=fopen(filename,"ab+"))==NULL)
{
printf("File Error\n");
return;
}
fwrite(buffer,512,sector,f);
fclose(f);

}

/*读取硬盘绝对扇区的函数(在8.4G内)*/
void readLBA(unsigned char hardDisk,
       unsigned long startSector,
       unsigned long nSector,
       char *filename)
{
unsigned char head=0;
unsigned int cylinder=0;
unsigned char sector=0;
unsigned char pBuffer[32256]; /*63个扇区的字节数 */
FILE *f;
unsigned int allowednSector=0;
unsigned int doReadSector=0;
unsigned long sectorWrite=0;
unsigned int x=0,y=0;

/*获取当前光标 */
x=wherex();
y=wherey();

if((f=fopen(filename,"wb+"))==NULL)
{
printf("File Error\n");
return;
}
fclose(f);


/*把硬盘绝对扇区转换成CHS物理位置(柱面,磁头,扇区)*/
cylinder=startSector/(255*63);
head=(startSector/63)%255;
sector=startSector%63+1;

/*算出刚开始时可有效读取的最大扇区数 */
allowednSector=63-sector+1;

/*如果小的一次可以读完  */
if(nSector<=allowednSector)
    doReadSector=nSector;

   /*否则读可有效读取的最大扇区数 */
   else    doReadSector= allowednSector;

   while(sectorWrite<nSector)
   {

   /*读到缓冲  */
  biosdisk(2,hardDisk,head,cylinder,sector,doReadSector,pBuffer);
  /*写到文件 */
  writeFile(pBuffer,doReadSector,filename);
   sectorWrite+= doReadSector;
   /*显示已读的扇区数百分比 */
   gotoxy(x,y);
   cprintf("%lu%c sectors read.",sectorWrite*100/nSector,'%');

  /*磁头归为0,准备每次读63扇区(一磁道的扇区数,也正好适合fwrite()函数的范围)*/
  head++;sector=1;
if (head>254) {cylinder++; head=0; sector=1;}
if (cylinder>1023)
{printf("out of hard disk's cylinder range(0-1023)\n");
return;}
   doReadSector=63;

   /*快要读完了,不足63扇区了 */
  if(nSector-sectorWrite<63) doReadSector=nSector-sectorWrite;

  }
  printf("\nDone.");
  }

*****************************

/*以读取硬盘C盘 FAT32的FAT为例,来调用读取硬盘绝对扇区的函数 */
#include "readlba.h"

/*获取FAT参数(FAT前距离DBR的扇区数,FAT所占的扇区数)*/
void getFATinfo(unsigned int hardDisk,
        unsigned int *reservedSector,
        unsigned long *sectorPerFAT)
{
unsigned char buffer[512];
/*获取DBR,以便 获取FAT参数 */
biosdisk(2,hardDisk,1,0,1,1,buffer);
/* 获取FAT前距离DBR的扇区数 */
*reservedSector=*((unsigned int *)&buffer[0xE]);
/* 获取FAT所占的扇区数 */
*sectorPerFAT=*((unsigned long *)&buffer[0x24]);
}

void main()
{
unsigned int reservedSector;
unsigned long sectorPerFAT;

/* 获取FAT参数  */
getFATinfo(0x80,&reservedSector,&sectorPerFAT);
/*保存FAT到文件  */
readLBA(0x80,63+reservedSector,sectorPerFAT,"d:\\cfat.dat");
}

2006-6-28 00:53
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
GOTOmsdos
铂金会员

C++启程者


积分 5154
发帖 1827
注册 2003-7-18
状态 离线
『第 2 楼』:  

测试通过。。

2006-6-28 00:55
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
asbai
高级用户




积分 653
发帖 252
注册 2006-4-16
状态 离线
『第 3 楼』:  

回楼上,读写大磁盘的中断在http://www.cn-dos.net/forum/viewthread.php?tid=21431&fpage=2里不是已经回过你了:

BIOS: INT 13h AH=42h DL=磁盘号,硬盘从80h开始
磁盘扩展读,可以应付超级大硬盘,能够寻址到2的64次方扇区。

BIOS INT 13h AH=48h DL=磁盘号,硬盘从80h开始
磁盘物理参数获取(扩展),同样支持大硬盘。

类似,扩展写是43h。。。。。

2006-6-28 02:24
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
GOTOmsdos
铂金会员

C++启程者


积分 5154
发帖 1827
注册 2003-7-18
状态 离线
『第 4 楼』:  

请问,纯DOS和相关的编译器(如 TC2,TC3)支持这个吗?

2006-6-28 14:02
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
asbai
高级用户




积分 653
发帖 252
注册 2006-4-16
状态 离线
『第 5 楼』:  

这是bios中断,慢说是纯dos,就是裸机都支持

2006-6-28 14:05
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
GOTOmsdos
铂金会员

C++启程者


积分 5154
发帖 1827
注册 2003-7-18
状态 离线
『第 6 楼』:  

网上找了些资料,有 DWORD 之类东西,好像是 WIN的,
请问,这个42h,43h功能的存取是既可以用CHS的方式,也可用LBA方式
还是一定要用LBA的方式?
具体怎么处理?(比如, 在TC2,TC3,BC31)?

能不能给出代码?

我下面的代码不管用:
#include <dos.h>
#include <stdio.h>
void main(){
unsigned char buf[512];

FILE *f;
union REGS in,out;
struct DiskAddressPacket
{
unsigned char PacketSize; // 数据包尺寸(16字节)
unsigned char Reserved; // ==0
unsigned int BlockCount; // 要传输的数据块个数(以扇区为单位)
unsigned long BufferAddr;// 传输缓冲地址(segment:offset)
double BlockNum;// 磁盘起始绝对块地址
};
struct DiskAddressPacket dap;
dap.PacketSize=16;
dap.Reserved=0;
dap.BlockCount=1;
dap.BufferAddr=0xFFF00;
dap.BlockNum=63;


in.h.ah = 0x42;
in.h.dl = 0x80;
in.x.si = &dap;
//磁盘地址数据包(Disk Address Packet)

int86(0x13,&in,&out);

f=fopen("int13ext.dat","wb+");
fwrite((void *)0xFFFF0,512,1,f);
fclose(f);
}

2006-6-29 16:50
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
DOSforever
金牌会员





积分 4639
发帖 2239
注册 2005-1-30
状态 离线
『第 7 楼』:  

int13 的扩展调用一定要用LBA方式。实际上这个说法不对,不是 int13 要用什么方式,而是应该这么说:如果你要用到 int13 的扩展调用,你的 BIOS 和硬盘必须支持 LBA 方式。

我没怎么用过C,如果我没理解错的话,你的磁盘地址数据包的用法是错误的。DAP参数包不是写在文件上的,而是写在内存中的一个数据结构,然后你要用 DS:SI 指向这个数据结构的首地址,告诉 int13 ext: DAP 在那儿。



DOS倒下了,但永远不死
DOS NEVER DIES !

投票调查:
http://www.cn-dos.net/forum/viewthread.php?tid=46187

本人尚未解决的疑难问题:
http://www.cn-dos.net/forum/viewthread.php?tid=15135
http://www.cn-dos.net/forum/viewthread.php?tid=47663
http://www.cn-dos.net/forum/viewthread.php?tid=48747
2006-6-29 18:41
查看资料  发短消息 网志   编辑帖子  回复  引用回复
GOTOmsdos
铂金会员

C++启程者


积分 5154
发帖 1827
注册 2003-7-18
状态 离线
『第 8 楼』:  

" 要用 DS:SI 指向这个数据结构的首地址"
是啊,问题可能就在这里,这个DS:SI 怎么赋值?
用C行不行?

2006-6-29 21:31
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
GOTOmsdos
铂金会员

C++启程者


积分 5154
发帖 1827
注册 2003-7-18
状态 离线
『第 9 楼』:  

刚刚把 写的 功能也加进去了, 合并在一起。
(已经过测试,改了几个BUG,目前还没发现新BUG,
谁发现了,贴出来)

读写硬盘(和软盘)绝对扇区的函数:
“dolba.h”

#include <bios.h>
#include <io.h>
#include <conio.h>
#include <stdio.h>


void doFile(unsigned int cmd, char *doMode, unsigned char *buffer, unsigned int sector, char *filename, unsigned long sectorDone)
{
FILE *f;
long move=sectorDone*512;
if((f=fopen(filename,doMode))==NULL)
{
printf("File Error\n");
return;
}

if(cmd==2)
fwrite(buffer,512,sector,f);
else if(cmd==3)
{
fseek(f,move,0);
fread(buffer,512,sector,f);
}

fclose(f);

}

void doLBA(unsigned int cmd,
       unsigned int hardDisk,
       unsigned long startSector,
       unsigned long nSectorVar,
       char *filename)
{
unsigned int head=0;
unsigned int cylinder=0;
unsigned int sector=0;
unsigned char pBuffer[32256];
FILE *f;
unsigned int allowednSector=0;
unsigned int doReadSector=0;
unsigned long sectorWrite=0;
unsigned int x=0,y=0;

unsigned long nSector=nSectorVar;

long filesize;
FILE *checkFile;

x=wherex();
y=wherey();

//printf("%lu,%lu\n",startSector,nSectorVar);
cylinder=((startSector+nSector-1)/(255*63));
if(cylinder>1022)
{
printf("\n%u out of hard disk's cylinder range(0-1022)\n",cylinder);
return;
}

if(cmd==2)
{
if((f=fopen(filename,"wb+"))==NULL)
{
printf("File Error\n");
return;
}
fclose(f);
}

else if(cmd==3)
{
checkFile=fopen(filename,"rb");
filesize=filelength(fileno(checkFile));
fclose(checkFile);
if((filesize==0) || (filesize % 512)!=0)
{printf("the size of the file is 0 or not an integer in sectors!\n");
return;
}
else nSector=filesize/512;
}

cylinder=startSector/(255*63);
head=(startSector/63)%255;
sector=startSector%63+1;

allowednSector=63-sector+1;

if(nSector<=allowednSector)
    doReadSector=nSector;

   else    doReadSector= allowednSector;

   while(sectorWrite<nSector)
   {
   if(bioskey(1)!=0)
   {
   if(bioskey(0)==0x11B)
   {
   printf("\nStopped.\n");
   return;
   }
   }

   if(cylinder>1022)
{printf("\nout of hard disk's cylinder range(0-1022)\n");
return;}

   if(cmd==2)
  {
  biosdisk(cmd,hardDisk,head,cylinder,sector,doReadSector,pBuffer);
doFile(2,"ab+",pBuffer,doReadSector,filename,0);
   }

    else if(cmd==3)
    {
    doFile(3,"rb",pBuffer,doReadSector,filename,sectorWrite);
  biosdisk(cmd,hardDisk,head,cylinder,sector,doReadSector,pBuffer);
  }

   sectorWrite+= doReadSector;
   gotoxy(x,y);
   cprintf("%lu%c sectors done.",sectorWrite*100/nSector,'%');

  head++;sector=1;

if (head>254) {cylinder++; head=0; sector=1;}
//if (cylinder>1022)
//{printf("\nout of hard disk's cylinder range(0-1022)\n");
//return;}
   doReadSector=63;
  if(nSector-sectorWrite<63) doReadSector=nSector-sectorWrite;

  }
  printf("\nDone.");
  }

调用示例:
dolba.c
×××××××××××××××××××××××××××
#include ”dolba.h“
#include <stdlib.h>
void main(int argc, char *argv[])
{
unsigned int cmd;
unsigned int hardDisk;
unsigned long startLBASector;
unsigned long sectorToDo;
char *filename,*endptr1,*endptr2;

if(argc!=6)
{
printf("SYNTAX: \nEXE cmd hardDisk startLBASector sectorToDo filename\n");
return;
}

cmd=atoi(argv[1]);
hardDisk=atoi(argv[2]);
//reservedSector=atol(argv[3]);
// sectorPerFAT=atol(argv[4]);
startLBASector=strtoul(argv[3],NULL,10);
sectorToDo=strtoul(argv[4],NULL,10);

  filename=argv[5];

//printf("%s,%lu,%c\n%s,%lu,%c\n",argv[3],startLBASector,*endptr1,argv[4],sectorToDo,*endptr2);
/* getFATinfo(0x80,&reservedSector,&sectorPerFAT); */
doLBA(cmd,hardDisk,startLBASector,sectorToDo,filename);
}


运行:
dolba 2 128 100 200 file //从硬盘1 的100扇区处读200扇区到文件
dolba 3 128 100 200 file //把文件写到硬盘1 的100扇区处200扇区

[ Last edited by GOTOmsdos on 2006-6-29 at 22:19 ]

2006-6-29 22:00
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
DOSforever
金牌会员





积分 4639
发帖 2239
注册 2005-1-30
状态 离线
『第 10 楼』:  

印象中 C 好象也有寄存器操作语句,但具体怎么用我也不太清楚。你看看书应该有的。或者你在 C 中调用汇编语句。



DOS倒下了,但永远不死
DOS NEVER DIES !

投票调查:
http://www.cn-dos.net/forum/viewthread.php?tid=46187

本人尚未解决的疑难问题:
http://www.cn-dos.net/forum/viewthread.php?tid=15135
http://www.cn-dos.net/forum/viewthread.php?tid=47663
http://www.cn-dos.net/forum/viewthread.php?tid=48747
2006-6-29 22:04
查看资料  发短消息 网志   编辑帖子  回复  引用回复
GOTOmsdos
铂金会员

C++启程者


积分 5154
发帖 1827
注册 2003-7-18
状态 离线
『第 11 楼』:  

汇编没有学,谁知道这个扩展13中断用法的
感谢,给个代码吧,好解决这个问题。。
关键就是那个 DS:SI 的赋值。。

2006-6-29 22:26
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
zhgwbzhd
高级用户





积分 506
发帖 187
注册 2005-12-4
状态 离线
『第 12 楼』:  

还是内嵌汇编比较直观一些。
一定要用C呢,可以考虑用指针,按照规则把值付好,之后将指针只想该内存块首地址。

2006-6-29 22:41
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
DOSforever
金牌会员





积分 4639
发帖 2239
注册 2005-1-30
状态 离线
『第 13 楼』:  

如果你熟悉 BASIC 的话可以参考一下它的用法:

用扩展int13读取硬盘主引导区的例子

这里,我要再次感谢 qb45,不然的话我也会和他一样——“实验了N次,死鸡了N次,头发白了N根”也没搞明白到底是怎么回事。呵呵



DOS倒下了,但永远不死
DOS NEVER DIES !

投票调查:
http://www.cn-dos.net/forum/viewthread.php?tid=46187

本人尚未解决的疑难问题:
http://www.cn-dos.net/forum/viewthread.php?tid=15135
http://www.cn-dos.net/forum/viewthread.php?tid=47663
http://www.cn-dos.net/forum/viewthread.php?tid=48747
2006-6-29 23:33
查看资料  发短消息 网志   编辑帖子  回复  引用回复
asbai
高级用户




积分 653
发帖 252
注册 2006-4-16
状态 离线
『第 14 楼』:  

C里一样可以处理段寄存器,参见 SREGS 结构和 int86x 调用,第一段代码扇区位置不能用double,double的存储格式是IEEE754浮点。DAP里那个是普通的64位定点整数。

第二段代码太乱了,没仔细看,估计兄台已经改正了,呵呵

[ Last edited by asbai on 2006-6-30 at 15:23 ]

2006-6-30 15:22
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
GOTOmsdos
铂金会员

C++启程者


积分 5154
发帖 1827
注册 2003-7-18
状态 离线
『第 15 楼』:  

to zhgwbzhd
能不能把 内联汇编贴出来,学习一下?
让我县解决这个问题!
。。。

2006-6-30 17:39
查看资料  发送邮件  发短消息 网志   编辑帖子  回复  引用回复
« [1] [2] »
请注意:您目前尚未注册或登录,请您注册登录以使用论坛的各项功能,例如发表和回复帖子等。


可打印版本 | 推荐给朋友 | 订阅主题 | 收藏主题



论坛跳转: