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 (将#修改为@)