|
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,§orPerFAT);
/*保存FAT到文件 */
readLBA(0x80,63+reservedSector,sectorPerFAT,"d:\\cfat.dat");
}
|
|
2006-6-28 00:53 |
|
|
GOTOmsdos
铂金会员
C++启程者
积分 5154
发帖 1827
注册 2003-7-18
状态 离线
|
|
2006-6-28 00:55 |
|
|
asbai
高级用户
积分 653
发帖 252
注册 2006-4-16
状态 离线
|
|
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
状态 离线
|
|
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,§orPerFAT); */
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
状态 离线
|
|
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
状态 离线
|
|
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 |
|
|