阅读:1577回复:7
怎样在程序里格式化磁盘?用户被禁言,该主题自动屏蔽! |
|
最新喜欢:![]() |
沙发#
发布于:2004-11-14 01:39
以上是在驱动中格式化FAT32的源代码,根据FAT32规格编写的。由于NTFS Microsoft没有公布其技术细节,所以,不好做,不过你可以自己研究,如果研究出来,也告诉我一声喔。
可以给点分给我吧! |
|
|
板凳#
发布于:2004-11-14 01:33
PBOOT_SECTOR bootSector;
NTSTATUS status = STATUS_SUCCESS; IO_STATUS_BLOCK ioStatus; CCHAR szVolLabel[] = "FILEBAKCUP "; ULONG totSectorCounts; LARGE_INTEGER curSysTime; PUCHAR tempBuffer = NULL; LARGE_INTEGER offset; // 格式化时,BPB, FAT分区表写入偏移量 ULONG RootDirSectors = 0; ULONG TmpVal1, TmpVal2, FATSz, i; DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ("FormatDisk -- IN \n" ) ); PAGED_CODE(); ASSERT( pdx->DiskImage != NULL ); totSectorCounts = (ULONG)(pdx->diskInfo.DiskSize.QuadPart / SECTOR_SIZE); bootSector = (PBOOT_SECTOR)pdx->DiskImage; memset(bootSector,0, SECTOR_SIZE); tempBuffer = (PUCHAR)pdx->DiskImage + SECTOR_SIZE; // 0 3 // 跳到引导代码,3个字节是根据Jmp汇编代码而来的,通常有以下两种方式 // jmpBoot[0] = 0xEB, jmpBoot[1] = 0x??, jmpBoot[2] = 0x90 and // jmpBoot[0] = 0xE9, jmpBoot[1] = 0x??, jmpBoot[2] = 0x?? // 0x??表示一个8bit的字节,在Format时0xEB更为常用 bootSector->BS_jmpBoot[0] = 0xEB; bootSector->BS_jmpBoot[1] = 0x58; bootSector->BS_jmpBoot[2] = 0x90; // 3 8 // 对于“MSWIN4.1” 通常存在误解,这个值仅仅是一个String而已,Microsoft // 操作系统通常并不关注这个值,但是某些Driver会关注这个值,所以为了保持 // 最大的兼容,通常推荐使用“MSWIN4.1”,如果不这样填充,也许某些Driver将 // 不能识别这个文件系统 strncpy(bootSector->BS_OEMName, "MSWIN4.1", 8); // 11 2 // 每个Sector有多少个Bytes,该字段只能填写下面的值:512、1024、2048、4096 // 但是如果你为了和老的文件系统实现保持最大兼容,你必须填充该字段512 // 有许多FAT代码硬性将此字段填为512,不要为此字段是否是512费劲疤瘌的check // Microsoft的OS对于512、1024、2048、4096都支持 bootSector->BPB_BytsPerSec = SECTOR_SIZE; // 13 1 // 每个镞的Sector数;该字段的值一定是2的倍速,但不能是0,可以是1、2、4、8 // 16、32、64和128,注意,无论如何不能用该值来推导“Bytes of Cluster”的值 // 大于32K((BPB_BytsPerSec * BPB_SecPerClus)),这里有个误区,即认为 // “Bytes of Cluster”的值大于32K就是OK,如果这个值大于32K,FAT表将不能正常 // 工作,有些系统支持每个镞为64K,但此时很多应用程序不能正常工作。 //if(totSectorCounts < DskTableFAT32[0]) // return; 暂时不判断,AP层已经做限制,需要自定义一个错误号 for( i = 0; i < sizeof(DskTableFAT32)/sizeof(DskTableFAT32[0]); i++) { if( totSectorCounts < DskTableFAT32.DiskSize ) { bootSector->BPB_SecPerClus = DskTableFAT32.SecPerClusVal; break; } } DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "The Value of Sector Per Cluster is: %d\n", bootSector->BPB_SecPerClus )); // 14 2 // 保留扇区数,在一个卷上的保留区域,这个数目从一个卷的第一个扇区算起. // 这个字段的值不能为0。对于FAT12和FAT16,这个值不能大于1,对于FAT32,这个 // 字段的值通常为32。对于FAT12和FAT16,许多系统硬性规定该值为1,但Microsfot // OS支持任何非零值 bootSector->BPB_ResvdSecCnt = 32; // 16 1 // FAT表的个数。对于任何类型的FAT卷,这个字段的值应该总是包含2。虽然任何大于 // 1的值都是有效的,对于2以外的任何值,可能部分os和相当多的软件都能正常工作。 // Microsfof的所有文件系统driver都支持2以外的其他值,但还是强烈推荐设置该值为2。 // 原因是需要为FAT表提供冗余,以防如果有扇区坏掉则可以从备份FAT表复制原来的 // 数据。有些Flush Memory Card为了节约空间,将此值设为1,这将导致某些软体不能 // 正常工作。 bootSector->BPB_NumFATs = 2; // 17 2 // 对于FAT12和FAT16,该字段的值是一个32Bytes的根目录入口的个数,对于FAT32,该 // 字段的值应该设置为0。为了保持最大兼容,FAT12和FAT16应该将此值设为512 bootSector->BPB_RootEntCnt = 0; // 19 2 // 对于FAT16,这个值应该是一个16bits的数,描述该卷上的所有Sector的个数,包括 // 4个区域。这个值可以是0,但此时BPB_TotSec32必须不为0。对于FAT12和FAT16卷, // 这个值是改卷上扇区个数,如果这个个数合适(应该少于0x10000)的话 // BPB_TotSec32值为0。 bootSector->BPB_TotSec16 = 0; // 21 1 // 0xF8是标准的表示一个不可移动的Fixed Media。对于可移动的Media,经常设置 // 为0xF0, 这个值可以是0xF0, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE以及 // 0xFF. 重要的一点是填充的这个值必须被相同的填充到FAT[0]。Msdos1.0对这个 // 值的进行检测,但是现在已经没有什么用了。 bootSector->BPB_Media = 0xf8; // 22 2 // 这个值描述一个FAT12和FAT16的FAT表占用的扇区数。对于FAT32这个值是0,用 // BPB_FATSz32来描述FAT32的FAT表占用的扇区数。 bootSector->BPB_FATSz16 = 0; // 24 2 // 每个磁道上的Sector数For Int 13,这个字段只和哪些需要有磁盘物理结构的Media // 相关。(磁盘物理结构即Disk Geometry)。磁盘卷最终被很多的磁头和柱面分解。 // 当发生Int 13时可以看见。 bootSector->BPB_SecPerTrk = 0x3f; // 26 2 // 磁头数目 for int 13,于这个字段相关的是早期对BPB_SecPerTrk的讨论。这个 // 字段包含一个基于"Counts of Heads",比如1.44M的3.5英寸软盘的该值为2。 bootSector->BPB_NumHeads = 2/*0xff*/; // 28 4 // 前述的包含该FAT卷的分区中的隐藏扇区数。该字段通常只为哪些希望在调用int 13 // 时可见的media。这个值总是应该被设置为0,对于没有被partitioned的Media。 // 严格的说来,什么值适合该字段由操作系统说了算。 bootSector->BPB_HiddSec = 0x3f; //32 4 // 一个FAT32卷上的扇区个数,是个32bits值。对于FAT12和FAT16卷,该值必须为零 // 对于一个FAT32卷,该值不能为0。该值必须大于0x10000。 bootSector->BPB_TotSec32 = totSectorCounts; // 36 4 // 一个FAT32卷上一个FAT表占用的Sector数。BPB_FATSz16必须被设置为0。 RootDirSectors = ((bootSector->BPB_RootEntCnt *32) + (bootSector->BPB_BytsPerSec -1)) / bootSector->BPB_BytsPerSec; TmpVal1 = bootSector->BPB_TotSec32 - (bootSector->BPB_ResvdSecCnt + RootDirSectors); TmpVal2 = (256 * bootSector->BPB_SecPerClus) + bootSector->BPB_NumFATs; TmpVal2 = TmpVal2 / 2; bootSector->BPB_FATSz32 = (TmpVal1 + (TmpVal2-1)) / TmpVal2; DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "The size of ONE FAT is: %d\n", bootSector->BPB_FATSz32 )); // 40 2 // Bits 0-3 -- 从0起的描述被激活的FAT。只有在镜像被禁止时有效 // Bits 4-6 -- 保留. // Bit 7 -- 0 表示一个FAT被镜像到所有所有FAT,当在运行时。 // -- 1 表示一个FAT被激活。该值作为1-3位的一个参考值。 // Bits 8-15 -- 保留 // bootSector->BPB_ExtFlags = 0; // 42 2 // FAT32卷的版本号,高字节位用来表示主版本,低字节表示副版本号。该值在FAT12 // 和FAT16上没有意义。该字段的设置是为了进行FAT32扩展时不出错。本文档定义0:0 // 如果该值为一个非0值,那么Back-level Windows Version将不会mount该卷。 // 注意: 磁盘应用设计时应尊重该值,不要去设置主副版本,如果在设计FAT32文件 // 系统Driver时没有版本号被定义,FAT32文件系统Driver必须Check该字段的值并且 // 不会Mount该卷, bootSector->BPB_FSVer = 0; // 44 4 // 根目录所在的第一个镞的镞号,通常为2,但不一定是2。在FAT12和FAT16上没有意义。 bootSector->BPB_RootClus = 2; //48 2 // 保存在该FAT32卷的保留区域的Info Sector占用的Sector数。通常为1。 // 该字段在FAT12和FAT16上没有意义。 bootSector->BPB_FSInfo = 1; //50 2 // 保存在该FAT32卷上的保留区域中的备份Boot Sector的扇区号。通常为6,不推荐 // 使用6以外的其他值。 在FAT12和FAT16上没有意义。 bootSector->BPB_BkBootSec = 6; //52 12 // 为未来扩展保留的,Code for Format FAT32应该总是填该区域为0。 // 在FAT12和FAT16上没有意义。 memset(bootSector->BPB_Reserved, 0, 12 ); //64 1 // 该字段与FAT12和FAT16上定义一样。Int 13 Drive Number(0x80)。该字段通常为 // 操作系统指定。0x00为Floppy,0x80为harddisk。与FAT12和FAT16唯一不一样的是 // 在bootSEctor中的偏移量不一样。 bootSector->BS_DrvNum = 0x80; //65 1 // 保留为Windows NT使用, Code for Format FAT32应该填0。 bootSector->BS_Reserved1 = 0; //66 1 // 扩展的Boot标志(0x29),该字段作为一个标志标识(indetify)接下来的3个字段。 bootSector->BS_BootSig = 0x29; //67 4 // 该卷的Serial Number,和下面一个字段结合使用,用来支持Removeable-Media的 // Volume Tracking。该字段通常被当前日期和时间填充。 bootSector->BS_VolID = 0x87654321; //71 11 // 该字段表示卷标,匹配11个字节。如果没有卷标时,填充"NO LABLE ". strncpy(bootSector->BS_VolLab, "NO NAME ",11 ); //82 8 // 对于FAT12和FAT16通常是“FAT12 ”, “FAT16 ”, or “FAT ”中的一个,对于 // FAT32,总是被设置为"FAT32 ",microsoft的文件 系统通常不用该字段来检测卷的 // FAT类型。但其他文件系统可能用该字段来检测。 strncpy(bootSector->BS_FilSysType, "FAT32 ", 8); //90 420 memset(bootSector->BS_Reserved2, 0, 420); //510 2 // 如果我们认为我们的Sector是按照Bytes排列,那么我们应该在bootsector[510] // 设置0x55,在bootsector[511]设置0xAA。 // 注意: 许多文档犯了一个错误,就是认为0xAA55占用了“Last 2 bytes of bootsector” // 这个说法只有在而起仅仅只有当BPB_BytsPerSec为512时成立。因为当设置512以外的 // 其他值时,0xAA55标志被设置的位置不会被改变,还是在510和511。 bootSector->BS_BootSig2 = 0xAA55; // 清零所有保留扇区 memset(tempBuffer, 0 , SECTOR_SIZE); for(i = 0; i < bootSector->BPB_ResvdSecCnt; i++) // BPB_ResvdSecCnt = 32; { offset.QuadPart = i * SECTOR_SIZE; status = ExdiskWriteFile( pdx->DiskPerfDeviceObject, &ioStatus, tempBuffer, SECTOR_SIZE, &offset ); if(!NT_SUCCESS(status)) { DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "Clear reserved sector failed, status: %lx\n", status )); return status; } } // 写入BootSector offset.QuadPart = 0; status = ExdiskWriteFile( pdx->DiskPerfDeviceObject, &ioStatus, bootSector, SECTOR_SIZE, &offset ); if(!NT_SUCCESS(status)) { DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "Write Boot Sector Failed, status: %lx\n", status )); return status; } // 写入备份BootSector offset.QuadPart = bootSector->BPB_BkBootSec * SECTOR_SIZE; status = ExdiskWriteFile( pdx->DiskPerfDeviceObject, &ioStatus, bootSector, SECTOR_SIZE, &offset ); if(!NT_SUCCESS(status)) { DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "Write Backup Boot Sector Failed, status: %lx\n", status )); return status; } ////////////////////////////////////////////////////////////////////////// // // TODO: Init Info Sector memset(tempBuffer, 0, SECTOR_SIZE); *(LONG *)(&tempBuffer[0]) = 0x41615252; *(LONG *)(&tempBuffer[484]) = 0x61417272; *(LONG *)(&tempBuffer[488]) = 0xFFFFFFFF; *(LONG *)(&tempBuffer[492]) = 0xFFFFFFFF; *(LONG *)(&tempBuffer[508]) = 0xAA550000; // 写入InfoSector offset.QuadPart = bootSector->BPB_FSInfo*SECTOR_SIZE; status = ExdiskWriteFile( pdx->DiskPerfDeviceObject, &ioStatus, tempBuffer, SECTOR_SIZE, &offset ); if(!NT_SUCCESS(status)) { DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "Write info Sector Failed, status: %lx\n", status )); return status; } // 备份Infor Sector offset.QuadPart = (bootSector->BPB_BkBootSec+ bootSector->BPB_FSInfo)*SECTOR_SIZE; status = ExdiskWriteFile( pdx->DiskPerfDeviceObject, &ioStatus, tempBuffer, SECTOR_SIZE, &offset ); if(!NT_SUCCESS(status)) { DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "Write info Sector Failed, status: %lx\n", status )); return status; } // 填写Info Sector后面一个Sector,只最后结束标志 memset(tempBuffer, 0, SECTOR_SIZE); ((PUCHAR)tempBuffer)[510] = 0x55; ((PUCHAR)tempBuffer)[511] = 0xAA; offset.QuadPart = (bootSector->BPB_FSInfo + 1) * SECTOR_SIZE; status = ExdiskWriteFile( pdx->DiskPerfDeviceObject, &ioStatus, tempBuffer, SECTOR_SIZE, &offset ); if(!NT_SUCCESS(status)) { DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "Write Backup Boot Sector Failed, status: %lx\n", status )); return status; } // 在备份Info Sector后面的,备份一个同样的Sector offset.QuadPart = (bootSector->BPB_BkBootSec + bootSector->BPB_FSInfo + 1) * SECTOR_SIZE; status = ExdiskWriteFile( pdx->DiskPerfDeviceObject, &ioStatus, tempBuffer, SECTOR_SIZE, &offset ); if(!NT_SUCCESS(status)) { DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "Write Backup Boot Sector Failed, status: %lx\n", status )); return status; } ////////////////////////////////////////////////////////////////////////// // // TODO: 填写FAT表 memset( tempBuffer, 0, SECTOR_SIZE); *(ULONG *)(&tempBuffer[0]) = 0x0ffffff8; // FAT[0]应该和MediaType一样F8 *(ULONG *)(&tempBuffer[4]) = 0xFFFFFFFF; *(ULONG *)(&tempBuffer[8]) = 0X0FFFFFFF; //root dir; // 写入FAT表1,偏移量为保留扇区数乘以SECTOR_SIZE offset.QuadPart = bootSector->BPB_ResvdSecCnt*SECTOR_SIZE; status = ExdiskWriteFile( pdx->DiskPerfDeviceObject, &ioStatus, tempBuffer, SECTOR_SIZE, &offset // FAT 1 offset, from reserved sectors end. ); if(!NT_SUCCESS(status)) { DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "Write FAT1 failed, status: %x\n", status )); return status; } // 将FAT1+1到FAT2之间的区域填0 memset(tempBuffer, 0, SECTOR_SIZE); for(i = bootSector->BPB_ResvdSecCnt + 1; i < bootSector->BPB_ResvdSecCnt + bootSector->BPB_FATSz32; i++) { offset.QuadPart = i*SECTOR_SIZE; status = ExdiskWriteFile( pdx->DiskPerfDeviceObject, &ioStatus, tempBuffer, SECTOR_SIZE, &offset // FAT 1 offset, from reserved sectors end. ); if(!NT_SUCCESS(status)) { DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "Clean FAT1 failed, status: %x\n", status )); return status; } } // 写入FAT表2,偏移量为(保留扇区数 + FAT表大小) * SECTOR_SIZE memset( tempBuffer, 0, SECTOR_SIZE); *(ULONG *)(&tempBuffer[0]) = 0x0ffffff8; // FAT[0]应该和MediaType一样F8 *(ULONG *)(&tempBuffer[4]) = 0xFFFFFFFF; *(ULONG *)(&tempBuffer[8]) = 0X0FFFFFFF; //root dir; offset.QuadPart = (bootSector->BPB_ResvdSecCnt + bootSector->BPB_FATSz32) * SECTOR_SIZE; status = ExdiskWriteFile( pdx->DiskPerfDeviceObject, &ioStatus, tempBuffer, SECTOR_SIZE, &offset // FAT 1 offset, from reserved sectors end. ); if(!NT_SUCCESS(status)) { DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "Write FAT2 failed, status: %x\n", status )); return status; } // 将FAT2+1到RootEntry之间的区域填0 memset(tempBuffer, 0, SECTOR_SIZE); for(i = bootSector->BPB_ResvdSecCnt + bootSector->BPB_FATSz32 + 1; i < bootSector->BPB_ResvdSecCnt + bootSector->BPB_FATSz32*2+1; i++) { offset.QuadPart = i*SECTOR_SIZE; status = ExdiskWriteFile( pdx->DiskPerfDeviceObject, &ioStatus, tempBuffer, SECTOR_SIZE, &offset // FAT 1 offset, from reserved sectors end. ); if(!NT_SUCCESS(status)) { DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "Clean FAT2 failed, status: %x\n", status )); return status; } } ////////////////////////////////////////////////////////////////////////// // // TODO: 填写根目录 memset( tempBuffer, 0, SECTOR_SIZE); strncpy(((PDIR_ENTRY)tempBuffer)->DIR_Name, "FILEBACKUP ", 11); ((PDIR_ENTRY)tempBuffer)->DIR_Attr = 0x08; // 写入根目录结构 offset.QuadPart = (bootSector->BPB_ResvdSecCnt + bootSector->BPB_FATSz32*bootSector->BPB_NumFATs) * SECTOR_SIZE; status = ExdiskWriteFile( pdx->DiskPerfDeviceObject, &ioStatus, tempBuffer, SECTOR_SIZE, &offset // FAT 1 offset, from reserved sectors end. ); if(!NT_SUCCESS(status)) { DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "Write dir failed, status: %x\n", status )); return status; } memset(tempBuffer, 0, SECTOR_SIZE); for(i = bootSector->BPB_ResvdSecCnt + bootSector->BPB_FATSz32*bootSector->BPB_NumFATs + 1; i < bootSector->BPB_ResvdSecCnt + bootSector->BPB_FATSz32*bootSector->BPB_NumFATs + bootSector->BPB_SecPerClus + 1; i++ ) { offset.QuadPart = i * SECTOR_SIZE; status = ExdiskWriteFile( pdx->DiskPerfDeviceObject, &ioStatus, tempBuffer, SECTOR_SIZE, &offset // FAT 1 offset, from reserved sectors end. ); if(!NT_SUCCESS(status)) { DBGPRINT( DBG_COMP_INIT, DBG_LEVEL_VERBOSE, ( "Clear dir failed, status: %x\n", status )); return status; } } return STATUS_SUCCESS; |
|
|
地板#
发布于:2004-11-09 10:10
偶比较笨的做法是自己按规范算~~~
|
|
地下室#
发布于:2004-11-08 14:26
自己实现应该比较麻烦
dos下就简单好多了,调用磁盘中断 |
|
|
5楼#
发布于:2004-11-08 13:00
用户被禁言,该主题自动屏蔽! |
|
6楼#
发布于:2004-11-08 09:51
做病毒?研究文件系统吧
|
|
|
7楼#
发布于:2004-11-08 09:29
这个我以前也考虑去做得,不过比较复杂。
一直也没成功。 |
|
|