如何以编程方式从C#更改Fat32分区的卷序列。我发现this example,但它是用C ++编写的,我读得不好。有人可以回答一个C#代码片段吗?
更新: 我可以看到上面例子中的C ++函数,我认为可以将端口指向C#
void CVolumeSerialDlg::ChangeSerialNumber(DWORD Drive, const DWORD newSerial)
{
const max_pbsi = 3;
struct partial_boot_sector_info
{
LPSTR Fs; // file system name
DWORD FsOffs; // offset of file system name in the boot sector
DWORD SerialOffs; // offset of the serialnumber in the boot sector
};
partial_boot_sector_info pbsi[max_pbsi] =
{
{"FAT32", 0x52, 0x43},
{"FAT", 0x36, 0x27},
{"NTFS", 0x03, 0x48}
};
TCHAR szDrive[12];
char Sector[512];
DWORD i;
sprintf(szDrive, "%c:\\", Drive & 0xFF);
if (!disk.Open(szDrive))
{
ShowErrorString("Could not open disk!");
return;
}
// read sector
if (!disk.ReadSector(0, Sector))
{
ShowErrorString("Could not read sector!");
return;
}
// try to search for a valid boot sector
for (i=0;i<max_pbsi;i++)
{
if (strncmp(pbsi[i].Fs, Sector+pbsi[i].FsOffs, strlen(pbsi[i].Fs)) == 0)
{
// we found a valid signature
break;
}
}
if (i >= max_pbsi)
{
MessageBox(_T("Cannot change serial number of this file system!"),
_T("Error"), MB_ICONERROR);
return;
}
// patch serial number
*(PDWORD)(Sector+pbsi[i].SerialOffs) = newSerial;
// write boot sector
if (!disk.WriteSector(0, Sector))
{
ShowErrorString("Could not write sector!");
return;
}
ShowErrorString("Volume serial number changed successfully!\r"
"You might want to restart your system for changes to take effect!");
}
答案 0 :(得分:5)
不保证,小心。
void ChangeSerialNumber(char volume, uint newSerial)
{
var fsInfo = new[]
{
new { Name = "FAT32", NameOffs = 0x52, SerialOffs = 0x43 },
new { Name = "FAT", NameOffs = 0x36, SerialOffs = 0x27 },
new { Name = "NTFS", NameOffs = 0x03, SerialOffs = 0x48 }
};
using (var disk = new Disk(volume))
{
var sector = new byte[512];
disk.ReadSector(0, sector);
var fs = fsInfo.FirstOrDefault(
f => Strncmp(f.Name, sector, f.NameOffs)
);
if (fs == null) throw new NotSupportedException("This file system is not supported");
var s = newSerial;
for (int i = 0; i < 4; ++i, s >>= 8) sector[fs.SerialOffs + i] = (byte)(s & 0xFF);
disk.WriteSector(0, sector);
}
}
bool Strncmp(string str, byte[] data, int offset)
{
for(int i = 0; i < str.Length; ++i)
{
if (data[i + offset] != (byte)str[i]) return false;
}
return true;
}
class Disk : IDisposable
{
private SafeFileHandle handle;
public Disk(char volume)
{
var ptr = CreateFile(
String.Format("\\\\.\\{0}:", volume),
FileAccess.ReadWrite,
FileShare.ReadWrite,
IntPtr.Zero,
FileMode.Open,
0,
IntPtr.Zero
);
handle = new SafeFileHandle(ptr, true);
if (handle.IsInvalid) Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
}
public void ReadSector(uint sector, byte[] buffer)
{
if (buffer == null) throw new ArgumentNullException("buffer");
if (SetFilePointer(handle, sector, IntPtr.Zero, EMoveMethod.Begin) == INVALID_SET_FILE_POINTER) Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
uint read;
if (!ReadFile(handle, buffer, buffer.Length, out read, IntPtr.Zero)) Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
if (read != buffer.Length) throw new IOException();
}
public void WriteSector(uint sector, byte[] buffer)
{
if (buffer == null) throw new ArgumentNullException("buffer");
if (SetFilePointer(handle, sector, IntPtr.Zero, EMoveMethod.Begin) == INVALID_SET_FILE_POINTER) Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
uint written;
if (!WriteFile(handle, buffer, buffer.Length, out written, IntPtr.Zero)) Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
if (written != buffer.Length) throw new IOException();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (handle != null) handle.Dispose();
}
}
enum EMoveMethod : uint
{
Begin = 0,
Current = 1,
End = 2
}
const uint INVALID_SET_FILE_POINTER = 0xFFFFFFFF;
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr CreateFile(
string fileName,
[MarshalAs(UnmanagedType.U4)] FileAccess fileAccess,
[MarshalAs(UnmanagedType.U4)] FileShare fileShare,
IntPtr securityAttributes,
[MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
int flags,
IntPtr template);
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint SetFilePointer(
[In] SafeFileHandle hFile,
[In] uint lDistanceToMove,
[In] IntPtr lpDistanceToMoveHigh,
[In] EMoveMethod dwMoveMethod);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadFile(SafeFileHandle hFile, [Out] byte[] lpBuffer,
int nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
[DllImport("kernel32.dll")]
static extern bool WriteFile(SafeFileHandle hFile, [In] byte[] lpBuffer,
int nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten,
[In] IntPtr lpOverlapped);
}
使用例如ChangeSerialNumber('D', 0x12345678);
答案 1 :(得分:4)
这是一个用于读取和写入序列号的小例子 FAT32卷。为了保持样本小,所有错误处理都被省略了。
请注意直接访问卷的扇区 可能导致数据丢失或损坏。所以要小心使用 以下示例(不是适合生产用途的示例)。 不保证!
在下面的示例中,我使用Win32 API GetDiskFreeSpace(使用.Net interop)来获取 FAT32卷的每个扇区的字节数。 要打开胖卷,我使用Win32 API CreateFile,因为FileStream类 不支持直接打开磁盘分区。
static uint GenericRead = 0x80000000;
static uint GenericWrite = 0x40000000;
static uint OpenExisting = 3;
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr SecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern bool GetDiskFreeSpace(string lpRootPathName, out uint lpSectorsPerCluster, out uint lpBytesPerSector, out uint lpNumberOfFreeClusters, out uint lpTotalNumberOfClusters);
static void ReadAndSetSerialNumber()
{
const string driveLetter = "e:"; // Drive with FAT32 file system.
uint sectorsPerCluster;
uint bytesPerSector;
uint numberOfFreeClusters;
uint totalNumberOfClusters;
GetDiskFreeSpace(String.Format(@"{0}\", driveLetter), out sectorsPerCluster, out bytesPerSector,
out numberOfFreeClusters, out totalNumberOfClusters);
Console.Out.WriteLine("Info for drive {0}", driveLetter);
Console.Out.WriteLine("Bytes per sector: {0}", bytesPerSector);
const int fatSerialOffset = 0x43;
const int fatIdOffset = 0x52;
const string fatFileSystemId = "FAT32";
using (SafeFileHandle sfh = CreateFile(String.Format("\\\\.\\{0}", driveLetter), GenericRead | GenericWrite,
(uint)FileShare.ReadWrite, IntPtr.Zero, OpenExisting, 0, IntPtr.Zero))
{
using (FileStream fs = new FileStream(sfh, FileAccess.ReadWrite))
{
byte[] firstSector = new byte[bytesPerSector];
fs.Read(firstSector, 0, (int)bytesPerSector);
if (Encoding.ASCII.GetString(firstSector, fatIdOffset, fatFileSystemId.Length) == fatFileSystemId)
{
Console.Out.WriteLine("FAT32 file system found...");
uint serial = BitConverter.ToUInt32(firstSector, fatSerialOffset);
Console.Out.WriteLine("Read serial number: {0:X4}-{1:X4}", serial >> 16, serial & 0xFFFF);
// Write new serial number.
byte[] newserial = BitConverter.GetBytes((uint)10000123);
Array.Copy(newserial, 0, firstSector, fatSerialOffset, newserial.Length);
fs.Seek(0, SeekOrigin.Begin);
fs.Write(firstSector, 0, (int)bytesPerSector);
}
}
}
}
此外,您可以使用.Net Framework的DriveInfo类来枚举 您计算机上的可用驱动器。
希望,这有帮助。