这是对我正在尝试做的事情的简短解释:
- 读取 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() 后值没有改变。
这只发生在备份扇区中。在主要部门内写作似乎有效。但由于主扇区和备份扇区的值不同,Windows 提示我再次格式化 USB 驱动器。
我正在使用 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, byte[] lpBuffer,
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, 0, 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, 0, ref newtmp, 0) == -1) //jump to zero, maybe unnecessary..
{
return false;
}
if (!WriteFile(exFatFileHandle, bufferMainBoot , 512, 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, ref newtmp, 0) == -1) //jump to zero at first, maybe unnecessary..
{
return false;
}
if (SetFilePointer(exFatFileHandle, 0x1800, ref newtmp, 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 , 512, out read, 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 , 100); //change values in sector buffer
if (SetFilePointer(exFatFileHandle, 0, ref newtmp, 0) == -1) //jump to zero at first, maybe unnecessary..
{
return false;
}
if (SetFilePointer(exFatFileHandle, 0x1800, ref newtmp, 0) == -1)//jump to sector 12 (Backup Boot Sector)
{
return false;
}
if (!WriteFile(exFatFileHandle, bufferBackupBoot , 512, out _, 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 的调用。