如何解决WriteFile() 到 exFAT 备份引导扇区对驱动器没有影响
这里是我正在尝试做的事情的简短说明:
- 读取 U 盘的 VolumeSerialNumber
- 增加 VolumeSerialNumber
- 将其写回闪存驱动器。
一般来说,它适用于使用 FAT 或 fat32 作为文件系统的 USB 驱动器,但我无法使用文件系统 exFAT。 正如在文件系统规范 (https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification) 中读到的那样,我已经做了一些似乎对 exFAT 必要的“特殊处理”:
- 在主引导扇区和备份引导扇区中将 VolumeFlag/VolumeDirty 设置为 true
- 读取、递增和写回主引导扇区和备份引导扇区中的序列号
- 重新计算并写回对应的主备校验和扇区中的BootChecksum
- 将两个扇区的 VolumeDirty 标志设置为 false。
我在尝试写入备份扇区时遇到一般问题。当我在调用 WriteFile() 之后调用 ReadFile() 时,我总是会取回旧值。 SetFilePointer() 似乎是正确的,因为我从 ReadFile() 获得了预期值/范围,但在调用 WriteFile() 后值没有改变。
这只会发生在备份扇区。在 Main 扇区内写入似乎有效。 但是由于主分区和备份分区中的最后值不同,Windows提示我重新格式化U盘。
我正在使用 C#/.Net 框架。 这是一个代码片段,也许可以更好地理解(不完整)。
[System.Runtime.InteropServices.DllImport("Kernel32.dll",SetLastError = true,CharSet = CharSet.Auto)]
static extern int SetFilePointer(
IntPtr hFile,int ldistancetoMove,ref int lpdistancetoMoveHigh,uint dwMoveMethod);
[DllImport("kernel32.dll",SetLastError = true)]
static extern bool WriteFile(IntPtr hFile,byte[] lpBuffer,uint nNumberOfBytesToWrite,out uint lpNumberOfBytesWritten,[In] ref System.Threading.NativeOverlapped lpOverlapped);
[DllImport("kernel32.dll",SetLastError = true)]
static extern bool ReadFile(IntPtr hFile,uint nNumberOfBytesToRead,out uint lpNumberOfBytesRead,IntPtr lpOverlapped);
[System.Runtime.InteropServices.DllImport("Kernel32.dll",SetLastError = true)]
private extern static IntPtr CreateFile(
String filename,UInt32 desiredAccess,UInt32 shareMode,IntPtr attributes,UInt32 creationdisposition,UInt32 flagsAndAttributes,IntPtr templateFile);
CloseHandle(...)
....
//example:
IntPtr exFatFileHandle = CreateFile(...);
//Set volume dirty flag...
///Starting with MainBoot
int tempOut = 0;
if (SetFilePointer(exFatFileHandle,ref tempOut,0) == -1)
{
return false;
}
byte[] bufferMainBoot = new byte[512];
uint read;
//reading first sector
if (!ReadFile(exFatFileHandle,bufferMainBoot,512,out read,IntPtr.Zero))
{
return false;
}
uint serial = BitConverter.ToUInt32(bufferMainBoot,100); //get Serial at postion 100 (0x64) and icrement++
seriaL++;
byte[] bytesSerial = BitConverter.GetBytes(serial); //return serial as 4 bytes
bytesSerial.copyTo(bufferMainBoot,100); //change values in sector buffer
if (SetFilePointer(exFatFileHandle,ref newtmp,0) == -1) //jump to zero,maybe unnecessary..
{
return false;
}
if (!WriteFile(exFatFileHandle,out _,ref over)) //write back first sector with changed serial
{
return false;
}
//Now the same for Backup Boot with different offset at read and write
int newtmp = 0;
if (SetFilePointer(exFatFileHandle,0) == -1) //jump to zero at first,maybe unnecessary..
{
return false;
}
if (SetFilePointer(exFatFileHandle,0x1800,0) == -1)//jump to sector 12 (Backup Boot Sector)
{
return false;
}
byte[] bufferBackupBoot = new byte[512];
uint read;
//reading first sector
if (!ReadFile(exFatFileHandle,bufferBackupBoot,IntPtr.Zero))
{
return false;
}
uint serial = BitConverter.ToUInt32(bufferBackupBoot,100); //get Serial at postion 100 (0x64) and icrement++
seriaL++;
byte[] bytesSerial = BitConverter.GetBytes(serial); //return serial as 4 byte value
bytesSerial.copyTo(bufferBackupBoot,0) == -1)//jump to sector 12 (Backup Boot Sector)
{
return false;
}
if (!WriteFile(exFatFileHandle,ref over)) //write back first sector with changed serial
{
return false;
}
//Same procedure as for calculating and writing Checksum to sector
// 0x1600,sector 11 (checksum sector of MainBoot) and
// 0x2E00,sector 23 (checksum sector of Backup Boot)
//Considering first 11 sectors for calculating the 32-Bit repeating checksum,should be right according to exFat specs.
//set volumeDirty back to false...
//CloseHandle(...)
提前感谢您的任何帮助或建议。
编辑 添加了 CreateFile、ReadFile、WriteFile、SetFilePointer.. 的调用。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。