我正在尝试理解和使用win32file。我需要掌握USN期刊,并且很难理解我在网上找到的代码段。这是我发现的代码片段-
format = 'qqqqqLLLLqqqqq'
length = struct.calcsize(format)
out_buffer = win32file.DeviceIoControl(volh, winioctlcon.FSCTL_GET_NTFS_VOLUME_DATA, None, length)
data = struct.unpack(format, out_buffer)
现在,对于C及其结构,我真的很生锈。我现在了解的是format
是96字节的缓冲区,它将从DeviceIoControl
因此,我尝试将格式更改为'QQQQQQQQQQQQQQQQQQQ'
以查看会发生什么(因为我不太可能实际发生什么,所以可以看到),结果我这次得到了一个更大的out_buffer
。所以我想打开它的包装-
struct.unpack(format, out_buffer)
让我惊讶的是,我-
struct.error: unpack requires a string argument of length 152
因此,我添加了另一个“ Q”来增加大小并得到相同的结果。我不了解为什么“ qqqqqLLLLqqqqq”有效,而“ QQQQQQQQQQQQQQQQQQQQQ”无效。所以我的问题是-
我的理解是,如果缓冲区大于输出,我们可以解压缩,为什么解压缩不起作用?
每次我想从DeviceIoControl中获取内容时,我都必须记住这些格式吗?
将我带到资源上也将是一个额外的收获,因为我需要以代码为基础来阅读USN期刊,而且我认为尝试后尝试不会带我到任何地方
答案 0 :(得分:2)
让我们将问题分成小块,然后每次都做。
win32file 模块是[GitHub]: mhammond/pywin32 - Python for Windows (pywin32) Extensions的一部分,该模块是 WinAPI s
上的 Python 包装器不幸的是,它没有官方的文档页面(或者我不知道),所以下面是我所能找到的最好的页面(我已经使用了多年)。永远不会失败(但吸引力较小)的另一种方法是直接查看代码
[ActiveState]: win32file.DeviceIoControl是[MS.Docs]: DeviceIoControl function
DeviceIoControl 的行为有所不同,具体取决于 dwIoControlCode (参数2 nd )。对于 FSCTL_GET_NTFS_VOLUME_DATA ,它将使用卷特定数据填充缓冲区。来自[MSDN]: FSCTL_GET_NTFS_VOLUME_DATA control code:
lpOutBuffer
指向输出缓冲区的指针,NTFS_VOLUME_DATA_BUFFER(@ CristiFati: !!!损坏的 URL !!! )结构。与输入缓冲区中指定的文件标识符关联的文件记录在此缓冲区中返回。有关如何确定此缓冲区的正确大小的特定信息,请参考 NTFS_VOLUME_DATA_BUFFER 结构的文档的“备注”部分。
这是上述损坏的 URL 的替代方法:[MSDN]: NTFS_VOLUME_DATA_BUFFER structure。由于不确定该文件的有效期限,因此我在下面粘贴了结构定义(来自 Windows套件 8.1 : winioctl.h (行号 4987 )):
typedef struct {
LARGE_INTEGER VolumeSerialNumber;
LARGE_INTEGER NumberSectors;
LARGE_INTEGER TotalClusters;
LARGE_INTEGER FreeClusters;
LARGE_INTEGER TotalReserved;
DWORD BytesPerSector;
DWORD BytesPerCluster;
DWORD BytesPerFileRecordSegment;
DWORD ClustersPerFileRecordSegment;
LARGE_INTEGER MftValidDataLength;
LARGE_INTEGER MftStartLcn;
LARGE_INTEGER Mft2StartLcn;
LARGE_INTEGER MftZoneStart;
LARGE_INTEGER MftZoneEnd;
} NTFS_VOLUME_DATA_BUFFER, *PNTFS_VOLUME_DATA_BUFFER;
[Python 3]: struct - Interpret bytes as packed binary data模块,用于在二进制数据和“常规”数据之间进行转换。它包含所有格式字符的含义( q , Q , L 等)。您还可以查看[SO]: Python struct.pack() behavior了解更多(实际)详细信息
浏览完以上材料后,情况应该会更清楚。
一些注意事项:
我还准备了一个虚拟的 Python 示例。
code.py :
#!/usr/bin/env python3
import sys
import struct
import win32file
import win32api
import win32con
import winioctlcon
VOLUME_LETTER = "E"
FILE_READ_ATTRIBUTES = 0x0080
FILE_EXECUTE = 0x0020
vol_data_buf_fmt = "qqqqqLLLLqqqqq" # This is the format that matches NTFS_VOLUME_DATA_BUFFER definition (96 bytes). Note: Instead of each 'q' you could also use 'Ll' as 'LARGE_INTEGER' is an union
BINARY_FORMAT_LIST = [
vol_data_buf_fmt,
"QQQQQQQQQQQQQQQQQQQ",
]
def print_formats(): # Dummy func
print("Formats and lengths:")
for format in BINARY_FORMAT_LIST:
print(" {:s}: {:d}".format(format, struct.calcsize(format)))
def main():
#print_formats()
vol_unc_name = "\\\\.\\{:s}:".format(VOLUME_LETTER)
print("volume: ", vol_unc_name)
access_flags = FILE_READ_ATTRIBUTES | FILE_EXECUTE # Apparently, doesn't work without FILE_EXECUTE
share_flags = win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE # Doesn't work withou FILE_SHARE_WRITE
creation_flags = win32con.OPEN_EXISTING
attributes_flags = win32con.FILE_ATTRIBUTE_NORMAL
vol_handle = win32file.CreateFile(vol_unc_name, access_flags, share_flags, None, creation_flags, attributes_flags, None)
buf_len = struct.calcsize(vol_data_buf_fmt)
for i in [buf_len]:
print(" Passing a buffer size of: {:d}".format(i))
buf = win32file.DeviceIoControl(vol_handle, winioctlcon.FSCTL_GET_NTFS_VOLUME_DATA, None, i)
print(" DeviceIocontrol returned a {:d} bytes long {:}".format(len(buf), type(buf)))
out = struct.unpack_from(vol_data_buf_fmt, buf)
print("\n NumberSectors: {:}\n TotalClusters: {:}\n BytesPerCluster: {:}".format(out[1], out[2], out[6]))
win32api.CloseHandle(vol_handle)
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
输出:
(py35x64_test) e:\Work\Dev\StackOverflow\q053318932>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" ./code.py Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32 volume: \\.\E: Passing a buffer size of: 96 DeviceIocontrol returned a 96 bytes long <class 'bytes'> NumberSectors: 494374911 TotalClusters: 61796863 BytesPerCluster: 4096
不用说,将 TotalClusters 与 BytesPerCluster 相乘,我得到的的正确字节数(由 Win 报告) E:驱动器。