簡體   English   中英

Python 和 GetVolumeInformationW 和 GetDriveTypeW:列出所有磁盤並獲取磁盤信息和文件系統標志

[英]Python and GetVolumeInformationW and GetDriveTypeW: list all disks and get disk info and filesystem flags

在 python3 上使用 windows API: https : //docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumeinformationw

如何在不安裝任何其他外部模塊的情況下,通過這個函數GetVolumeInformationW獲取這些值(file_system_flags、max_component_length 和 serial_number)?

import ctypes

kernel32 = ctypes.windll.kernel32
volumeNameBuffer = ctypes.create_unicode_buffer(1024)
fileSystemNameBuffer = ctypes.create_unicode_buffer(1024)
serial_number = None
max_component_length = None
file_system_flags = None

target_disk = 'C:\\'
rc = kernel32.GetVolumeInformationW(
    ctypes.c_wchar_p(target_disk),
    volumeNameBuffer, ctypes.sizeof(volumeNameBuffer),
    serial_number,
    max_component_length,
    file_system_flags, 
    fileSystemNameBuffer, ctypes.sizeof(fileSystemNameBuffer)
)

mount_point = target_disk[:-1]
disk_label = volumeNameBuffer.value
fs_type = fileSystemNameBuffer.value
max_length = max_component_length
flags = file_system_flags
serial = serial_number

print(mount_point, disk_label, fs_type, max_length, flags, serial)

補充:如何將文件系統標志轉換為人類可讀的格式?

my_disk_flag = 0x3e706ff

hex_flags = [0x00000002, 0x00000001, 0x20000000, 0x00000010, 0x00040000, 0x00000008, 0x00080000, 0x00100000, 0x00020000, 0x00800000, 0x00400000, 0x00010000, 0x01000000, 0x00000080, 0x00000040, 0x00200000, 0x02000000, 0x00000004, 0x00008000, 0x00000020, 0x08000000]

str_flags = ['FILE_CASE_PRESERVED_NAMES', 'FILE_CASE_SENSITIVE_SEARCH', 'FILE_DAX_VOLUME', 'FILE_FILE_COMPRESSION', 'FILE_NAMED_STREAMS', 'FILE_PERSISTENT_ACLS', 'FILE_READ_ONLY_VOLUME', 'FILE_SEQUENTIAL_WRITE_ONCE', 'FILE_SUPPORTS_ENCRYPTION', 'FILE_SUPPORTS_EXTENDED_ATTRIBUTES', 'FILE_SUPPORTS_HARD_LINKS', 'FILE_SUPPORTS_OBJECT_IDS', 'FILE_SUPPORTS_OPEN_BY_FILE_ID', 'FILE_SUPPORTS_REPARSE_POINTS', 'FILE_SUPPORTS_SPARSE_FILES', 'FILE_SUPPORTS_TRANSACTIONS', 'FILE_SUPPORTS_USN_JOURNAL', 'FILE_UNICODE_ON_DISK', 'FILE_VOLUME_IS_COMPRESSED', 'FILE_VOLUME_QUOTAS', 'FILE_SUPPORTS_BLOCK_REFCOUNTING']

創建該類型的實例並通過引用傳遞它。 它相當於在 C 中聲明一個局部變量並傳遞它的地址,例如DWORD flags; 並作為&flags傳遞為輸出參數。

它還通過聲明函數調用的.argtypes.restype來幫助 ctypes 錯誤檢查,這類似於聲明 C 原型。 ctypes.wintypes有許多適用於 Windows 的預定義類型:

import ctypes as ct
from ctypes import wintypes as w

dll = ct.WinDLL('kernel32')
dll.GetVolumeInformationW.argtypes = w.LPCWSTR,w.LPWSTR,w.DWORD,w.LPDWORD,w.LPDWORD,w.LPDWORD,w.LPWSTR,w.DWORD
dll.GetVolumeInformationW.restype = w.BOOL

volumeNameBuffer = ct.create_unicode_buffer(w.MAX_PATH + 1)
fileSystemNameBuffer = ct.create_unicode_buffer(w.MAX_PATH + 1)
serial_number = w.DWORD()
max_component_length = w.DWORD() 
file_system_flags = w.DWORD()

target_disk = 'C:\\'

if dll.GetVolumeInformationW(target_disk,
                             volumeNameBuffer, ct.sizeof(volumeNameBuffer),
                             ct.byref(serial_number),
                             ct.byref(max_component_length),
                             ct.byref(file_system_flags),
                             fileSystemNameBuffer, ct.sizeof(fileSystemNameBuffer)):
    mount_point = target_disk[:-1]
    disk_label = volumeNameBuffer.value
    fs_type = fileSystemNameBuffer.value
    max_length = max_component_length.value
    flags = file_system_flags.value
    serial = serial_number.value

    print(f'{mount_point} {disk_label} {fs_type} {max_length} {flags:#x} {serial:#08x}')

為了將來參考,我將在此處留下有關如何列出所有磁盤並獲取其類似 fstab 的信息的完整代碼

import ctypes as ct
import string
from ctypes import wintypes as w
from enum import IntFlag
from pathlib import Path

class FSFlags(IntFlag):
    FILE_CASE_SENSITIVE_SEARCH        = 0x00000001
    FILE_CASE_PRESERVED_NAMES         = 0x00000002
    FILE_UNICODE_ON_DISK              = 0x00000004
    FILE_PERSISTENT_ACLS              = 0x00000008
    FILE_FILE_COMPRESSION             = 0x00000010
    FILE_VOLUME_QUOTAS                = 0x00000020
    FILE_SUPPORTS_SPARSE_FILES        = 0x00000040
    FILE_SUPPORTS_REPARSE_POINTS      = 0x00000080
    FILE_VOLUME_IS_COMPRESSED         = 0x00008000
    FILE_SUPPORTS_OBJECT_IDS          = 0x00010000
    FILE_SUPPORTS_ENCRYPTION          = 0x00020000
    FILE_NAMED_STREAMS                = 0x00040000
    FILE_READ_ONLY_VOLUME             = 0x00080000
    FILE_SEQUENTIAL_WRITE_ONCE        = 0x00100000
    FILE_SUPPORTS_TRANSACTIONS        = 0x00200000
    FILE_SUPPORTS_HARD_LINKS          = 0x00400000
    FILE_SUPPORTS_EXTENDED_ATTRIBUTES = 0x00800000
    FILE_SUPPORTS_OPEN_BY_FILE_ID     = 0x01000000
    FILE_SUPPORTS_USN_JOURNAL         = 0x02000000
    FILE_SUPPORTS_BLOCK_REFCOUNTING   = 0x08000000
    FILE_DAX_VOLUME                   = 0x20000000

def validate(result,func,args):
    if not result:
        raise ct.WinError(ct.get_last_error())
    return None

dll = ct.WinDLL('kernel32',use_last_error=True)
dll.GetVolumeInformationW.argtypes = w.LPCWSTR,w.LPWSTR,w.DWORD,w.LPDWORD,w.LPDWORD,w.LPDWORD,w.LPWSTR,w.DWORD
dll.GetVolumeInformationW.restype = w.BOOL
dll.GetVolumeInformationW.errcheck = validate

volumeNameBuffer = ct.create_unicode_buffer(w.MAX_PATH + 1)
fileSystemNameBuffer = ct.create_unicode_buffer(w.MAX_PATH + 1)
serial_number = w.DWORD()
max_component_length = w.DWORD() 
file_system_flags = w.DWORD()

lst_available_disks = [f'{d}:\\' for d in string.ascii_uppercase if Path(f'{d}:\\').exists()]
lst_disk_types = ['DRIVE_UNKNOWN', 'DRIVE_NO_ROOT_DIR', 'DRIVE_REMOVABLE', 'DRIVE_FIXED', 'DRIVE_REMOTE', 'DRIVE_CDROM', 'DRIVE_RAMDISK']

for target_disk in lst_available_disks:
    disk_type_index = dll.GetDriveTypeW(target_disk)

    dll.GetVolumeInformationW(target_disk,
                            volumeNameBuffer, ct.sizeof(volumeNameBuffer),
                            ct.byref(serial_number),
                            ct.byref(max_component_length),
                            ct.byref(file_system_flags),
                            fileSystemNameBuffer, ct.sizeof(fileSystemNameBuffer))

    mount_point = target_disk
    disk_label = volumeNameBuffer.value
    fs_type = fileSystemNameBuffer.value
    max_length = max_component_length.value
    flags = FSFlags(file_system_flags.value)
    serial = serial_number.value

    if 'FILE_READ_ONLY_VOLUME' in str(flags):
        read_write_status = 'ro'
    else:
        read_write_status = 'rw'

    extra_tab_label = ''
    if len(disk_label) < 8: extra_tab_label = '\t'
    extra_tab_type = ''
    if len(lst_disk_types[disk_type_index]) < 12: extra_tab_type = '\t'

    print(f'{disk_label}{extra_tab_label}\t{mount_point}\t{fs_type}\t{max_length}\t{serial}\t{read_write_status},{lst_disk_types[disk_type_index]}{extra_tab_type}\t{flags=}\n')

輸出(只需用零替換磁盤序列):

Win10           C:\     NTFS    255     0000000000      rw,DRIVE_FIXED          flags=<FSFlags.FILE_SUPPORTS_USN_JOURNAL|FILE_SUPPORTS_OPEN_BY_FILE_ID|FILE_SUPPORTS_EXTENDED_ATTRIBUTES|FILE_SUPPORTS_HARD_LINKS|FILE_SUPPORTS_TRANSACTIONS|FILE_NAMED_STREAMS|FILE_SUPPORTS_ENCRYPTION|FILE_SUPPORTS_OBJECT_IDS|1024|512|FILE_SUPPORTS_REPARSE_POINTS|FILE_SUPPORTS_SPARSE_FILES|FILE_VOLUME_QUOTAS|FILE_FILE_COMPRESSION|FILE_PERSISTENT_ACLS|FILE_UNICODE_ON_DISK|FILE_CASE_PRESERVED_NAMES|FILE_CASE_SENSITIVE_SEARCH: 65472255>     

                D:\     FAT32   255     0000000000      rw,DRIVE_FIXED          flags=<FSFlags.FILE_SUPPORTS_ENCRYPTION|512|FILE_UNICODE_ON_DISK|FILE_CASE_PRESERVED_NAMES: 131590>

DRV061107       E:\     CDFS    110     0000000000      ro,DRIVE_CDROM          flags=<FSFlags.FILE_SUPPORTS_OPEN_BY_FILE_ID|FILE_READ_ONLY_VOLUME|FILE_UNICODE_ON_DISK|FILE_CASE_SENSITIVE_SEARCH: 17301509>

Ventoy          F:\     exFAT   255     0000000000      rw,DRIVE_REMOVABLE      flags=<FSFlags.FILE_SUPPORTS_ENCRYPTION|512|FILE_UNICODE_ON_DISK|FILE_CASE_PRESERVED_NAMES: 131590>

VTOYEFI         G:\     FAT     255     0000000000      rw,DRIVE_REMOVABLE      flags=<FSFlags.FILE_SUPPORTS_ENCRYPTION|512|FILE_UNICODE_ON_DISK|FILE_CASE_PRESERVED_NAMES: 131590>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM