如何显式锁定已挂载的文件系统?
Posted
技术标签:
【中文标题】如何显式锁定已挂载的文件系统?【英文标题】:How to explicitly lock a mounted file system? 【发布时间】:2015-05-24 02:25:40 【问题描述】:如何在 Windows 7 中写入物理驱动器?
我正在尝试在 Windows 7 中写入物理磁盘(例如 \\.\PhysicalDrive0
)。
这个问题已经被问死了,但从未得到回答。它曾经在 Windows XP 中工作,但微软故意破坏了 Windows Vista。微软提供了有关如何做到这一点的提示,但甚至没有人能够弄清楚。
它曾经工作过
在过去,允许写入物理磁盘(只要您是管理员)。执行此操作的方法甚至记录在知识库文章中:
INFO: Direct Drive Access Under Win32
要在基于 Win32 的应用程序中打开物理硬盘驱动器以直接访问磁盘(原始 I/O),请使用以下形式的设备名称
\\.\PhysicalDriveN
其中 N 是 0、1、2 等,代表系统中的每个物理驱动器。
您可以使用带有这些设备名称的 CreateFile() 应用程序编程接口 (API) 打开物理或逻辑驱动器,前提是您对驱动器具有适当的访问权限(即,您必须是管理员)。您必须同时使用 CreateFile() FILE_SHARE_READ 和 FILE_SHARE_WRITE 标志才能访问驱动器。
所有这些都在 Windows Vista 中发生了变化,因为附加了安全限制。
如何写入物理磁盘?
许多人,许多答案,对许多***问题感到困惑:
写入物理磁盘(例如\\.\PhysicalDrive0
),以及
写入逻辑卷(例如\\.\C$
)
微软注意到restrictions placed on both kinds of operations:
阻止对卷和磁盘的直接写入操作
在 DASD(直接访问存储设备)卷句柄上的写操作将成功如果:
文件系统没有挂载,或者如果 写入的扇区是引导扇区。 要写入的扇区位于文件系统空间之外。 文件系统已通过请求独占写入权限被隐式锁定。 已通过发送锁定/卸载请求明确锁定文件系统。 内核模式驱动程序已标记写入请求,指示应绕过此检查。该标志称为 SL_FORCE_DIRECT_WRITE,它位于 IrpSp->flags 字段中。文件系统和存储驱动程序都会检查此标志。
在我的情况下,我问的是写一个Physical,而不是一个Logical。 Microsoft 注意到写入物理磁盘句柄的新限制:
我正在写入的扇区确实属于文件系统 --> 失败 我正在写入的扇区确实属于已安装、未锁定的文件系统 --> 失败 我正在写入的扇区确实位于已挂载的文件系统中,并且位于具有文件系统的逻辑卷中。在以下情况下,磁盘句柄上的写操作将成功:
写入的扇区不属于文件系统。 写入的扇区属于已挂载的文件系统,该文件系统已被明确锁定。 正在写入的扇区属于未安装的文件系统或卷没有文件系统。
关于如何使它工作的提示围绕着:
卸载文件系统 锁定文件系统但问题是如何卸载文件系统?如何锁定文件系统?
你现在在做什么?
我能够读取磁盘的所有物理扇区;那没问题。问题是当我想写入到磁盘的物理扇区时。
我的当前代码是伪代码:
void ZeroSector(Int64 PhysicalSectorNumber)
String diskName := '\\.\PhysicalDrive0';
DWORD desiredAccess := GENERIC_READ or GENERIC_WRITE;
//INFO: Direct Drive Access Under Win32
//https://support.microsoft.com/en-us/kb/100027
//says you nedd both
DWORD shareMode := FILE_SHARE_READ or FILE_SHARE_WRITE;
//Open the physical disk
hDisk := CreateFile(diskName, desiredAccess, shareMode,
nil, OPEN_EXISTING, 0, 0);
if hDisk = INVALID_HANDLE_VALUE
RaiseLastWin32Error();
try
Int32 bytesPerPhysicalSector := 4096; //Determined elsewhere using IOCTL_STORAGE_QUERY_PROPERTY+STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR
//Setup buffer for what we will be writing
Byte[] buffer = new Byte[bytesPerPhysicalSector];
//Calculate the byte offset of where the sector is
Int64 byteOffset = PhysicalSectorNumber * bytesPerPhysicalSector;
//Seek to that byte offset
SetFilePointer(hDisk, byteOffset.Lo, byteOffset.Hi, FILE_BEGIN);
//Write the buffer
DWORD numberOfBytesWritten;
if (!WriteFile(hDisk, buffer, bytesPerPhysicalSector, out numberOfBytesWritten, nil))
RaiseLastWin32Error();
finally
CloseHandle(hDisk);
令人惊讶的是:
我可以打开物理磁盘以供GENERIC_READ
+ GENERIC_WRITE
访问
直到实际的WriteFile
失败,它才会失败:
ERROR_ACCESS_DENIED
如何按照微软所说的去做
微软说我的写作会失败,他们是对的。他们说我需要明确锁定文件系统:
在以下情况下,磁盘句柄上的写操作将成功:
写入的扇区属于已挂载的文件系统,该文件系统已被明确锁定。
除非我不知道该怎么做。
我知道我可能必须使用DeviceIoControl
和IOCTLS
之一来“锁定”一个卷。但这带来了三个挑战:
忽略这些问题,我盲目地尝试了LockFile
API。就在致电WriteFile
之前:
//Try to lock the physical sector we will be writing
if (!LockFile(DiskHandle, byteOffset.Lo, byteOffset.Hi, bytesPerPhysicalSector, 0)
RaiseLastWin32Error();
失败了:
ERROR_INVALID_FUNCTION (1)
【问题讨论】:
【参考方案1】:查看 FSCTL_LOCK_VOLUME、FSCTL_DISMOUNT_VOLUME 控制代码。我相信您必须枚举磁盘上的所有卷,然后卸载并锁定它们。锁定成功后,磁盘就是你的了。
您可能无法在系统驱动器上执行此操作。我还猜想包含页面文件的卷会有一些警告。
完成此操作后,我可以写入相应的 \\.\PhysicalDrive3。我以前不能:
HANDLE hVol = CreateFileA(
"\\\\.\\X:",
FILE_READ_DATA | FILE_WRITE_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD unused;
BOOL b = DeviceIoControl(hVol, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &unused, NULL);
if (!b)
printf("%u", GetLastError());
abort();
...
HANDLE h = CreateFileA(
argv[1], // that's my \\physicaldrive3
FILE_READ_DATA | FILE_WRITE_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL);
...
bResult = WriteFile(h, buf, cb, &dwWritten, &foo);
if (!bResult)
// used to fail without messing with vol handle
printf("Failed writing data. Error = %d.\n", GetLastError());
return 0;
【讨论】:
稍有不同的是,您正在锁定一个 volume(即\\.\x:
),然后写入同一卷。在我的情况下,我想锁定/卸载卷,以便我可以写入 disk(即\\.\PhysicalDrive3
)。想象一下\\.\PhysicalDrive3
有多个卷(例如D:
、F:
)的情况。
我锁定卷(句柄 hVol),然后写入物理驱动器(句柄 h)。您必须枚举您的卷并检查它们在哪个驱动器上。
所以基本上这需要通过FindFirstVolume
枚举所有卷并查询IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
以查找包含目标磁盘范围(物理驱动器号和扇区范围)的卷。然后在尝试写入物理磁盘之前卸载或锁定所有受影响的卷。
是的,按照这些思路。
我想从这个答案链接到我的相关问题:***.com/questions/65225665 - 我正在解释这种方法的一个问题,并希望在我的情况下有一个更好的方法。以上是关于如何显式锁定已挂载的文件系统?的主要内容,如果未能解决你的问题,请参考以下文章