在Windows上,将原始数据写入物理磁盘(闪存驱动器)时出现“坏文件描述符”的错误-Python

6
我正在尝试在Windows(如果有关系,是10)上将USB闪存驱动器作为物理驱动器直接读取和写入数据。 我正在使用Python进行操作。
我遵循了以下讨论:
{{link1:使用Python在Windows下获取原始设备的写入访问权限}}
我遇到了与kcstrom在那个问题中所遇到的相同的问题。 我得到了一个

标签。
    Traceback (most recent call last):
    File "C:\script.py", line 49, in <module>
    disk.write(data)
    IOError: [Errno 9] Bad file descriptor

阅读和寻找工作应该按照要求进行,读取的数据是正确的。

我目前所知道的:

  1. 处理驱动器应该使用扇区大小的读/写/查找。
  2. 磁盘必须以'rb+'模式打开。
  3. 使用\\.\L:和\\.\PhysicalDriveN产生相同的结果。
  4. 脚本必须在管理员特权下运行。
  5. 卸载驱动器并尝试访问\\.\PhysicalDriveN文件时 - 即使以管理员身份运行,“权限被拒绝”。

复制错误:(警告:此代码可能会损坏物理驱动器,请仅在了解自己在做什么的情况下运行)

SOME_OFFSET = 123123
SOME_SIZE = 100
# replace L with the drive letter
disk = open('\\\\.\\L:','r+b')
# or use: (replace N with the drive number)
# disk = open('\\\\.\\PhysicalDriveN','r+b')
disk.seek(SOME_OFFSET*512)
data = disk.read(SOME_SIZE*512)
#modify data...
disk.seek(SOME_OFFSET*512)
disk.write(data)

我无法确定这是权限问题还是打开驱动器的方式有问题。


1
底层的 WriteFile 失败并显示 ERROR_ACCESS_DENIED。直接写入挂载的卷是不允许的。您需要深入了解此问题,锁定和卸载卷后才能将其写入或物理驱动器。 - Eryk Sun
@eryksun,你能告诉我如何获取所需的信息吗?谢谢! - MiaoHatola
1
你将使用CreateFile打开的卷句柄调用DeviceIoControl。这里是用于锁定、卸载和解锁卷的卷控制代码。在Python中,你可以使用ctypes或PyWin32的win32file模块。 - Eryk Sun
1
你得到了一个可行的解决方案吗? - Eryk Sun
@eryksun很抱歉,我没有时间让它在Windows上运行。为了在我有限的时间内使其正常工作,我已经转移到Linux,在那里使用/dev/sd*打开可以无缝运行。非常感谢您的帮助! - MiaoHatola
2
事实证明,在大多数情况下,所需的只是锁定音量。我将添加一个上下文管理器来完成这个任务。 - Eryk Sun
1个回答

6
根据MSDN技术笔记"阻止直接写入卷和磁盘的操作"
在文件系统未挂载或以下情况下,DASD卷处理中的写入操作将成功:
  • 被写入的扇区是引导扇区。
  • 被写入的扇区位于文件系统空间之外。
  • 通过请求独占写访问隐式锁定了文件系统。
  • 通过发送锁定/卸载请求显式锁定了文件系统。
在以下情况下,磁盘处理中的写入操作将成功:
  • 被写入的扇区不属于任何文件系统。
  • 被写入的扇区属于已显式锁定的已挂载文件系统。
  • 被写入的扇区属于未挂载的文件系统或卷没有文件系统。
这里是一个简单的上下文管理器,用于锁定卷。它使用 PyWin32 中的 win32filewinoctlcon 模块。
import msvcrt
import win32file
import winioctlcon
import contextlib

@contextlib.contextmanager
def lock_volume(vol):
    hVol = msvcrt.get_osfhandle(vol.fileno())
    win32file.DeviceIoControl(hVol, winioctlcon.FSCTL_LOCK_VOLUME,
                              None, None)
    try:
        yield vol
    finally:
        try:
            vol.flush()
        finally:
            win32file.DeviceIoControl(hVol, winioctlcon.FSCTL_UNLOCK_VOLUME,
                                      None, None)

if __name__ == '__main__':
    VOLUME_PATH = r'\\.\E:'
    OFFSET = 123123
    SIZE = 100

    with open(VOLUME_PATH, 'r+b') as disk:
        with lock_volume(disk):
            disk.seek(OFFSET * 512)
            data = disk.read(SIZE * 512)
            disk.seek(OFFSET * 512)
            disk.write(data)
            input('press enter to unlock the volume')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接