All pastes #2051584 Raw Edit

usbutils.py

public python v1 · immutable
#2051584 ·published 2011-04-28 15:17 UTC
rendered paste body
# Miro - an RSS based video player application# Copyright (C) 2010, 2011# Participatory Culture Foundation## This program is free software; you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation; either version 2 of the License, or# (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, write to the Free Software# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA## In addition, as a special exception, the copyright holders give# permission to link the code of portions of this program with the OpenSSL# library.## You must obey the GNU General Public License in all respects for all of# the code used other than OpenSSL. If you modify file(s) with this# exception, you may extend this exception to your version of the file(s),# but you are not obligated to do so. If you do not wish to do so, delete# this exception statement from your version. If you delete this exception# statement from all source files in the program, then also delete it here.import loggingimport ctypes, ctypes.wintypesimport _winregdef warn(what, code, message):    logging.warn('error doing %s (%d): %s', what, code, message)INVALID_HANDLE_VALUE = -1DIGCF_PRESENT = 0x00000002DIGCF_DEVICEINTERFACE = 0x00000010ERROR_INSUFFICIENT_BUFFER = 122ERROR_NO_MORE_ITEMS = 259MAXIMUM_USB_STRING_LENGTH = 255kernel32 = ctypes.windll.kernel32setupapi = ctypes.windll.setupapiSetupDiGetClassDevs = setupapi.SetupDiGetClassDevsWSetupDiEnumDeviceInterfaces = setupapi.SetupDiEnumDeviceInterfacesSetupDiGetDeviceInterfaceDetail = setupapi.SetupDiGetDeviceInterfaceDetailWCM_Get_Parent = setupapi.CM_Get_ParentCM_Get_Device_ID = setupapi.CM_Get_Device_IDWCM_Request_Device_Eject = setupapi.CM_Request_Device_EjectWclass GUID(ctypes.Structure):    _fields_ = [("Data1", ctypes.c_ulong),                ("Data2", ctypes.c_ushort),                ("Data3", ctypes.c_ushort),                ("Data4", ctypes.c_ubyte * 8)]    def __str__(self):        return '{%08X-%04X-%04X-%04X-%012X}' % (            self.Data1, self.Data2, self.Data3,            self.Data4[0] * 256 + self.Data4[1],            self.Data4[2] * (256 ** 5) +            self.Data4[3] * (256 ** 4) +            self.Data4[4] * (256 ** 3) +            self.Data4[5] * (256 ** 2) +            self.Data4[6] * 256 +            self.Data4[7])class SP_DEVINFO_DATA(ctypes.Structure):    _fields_ = [("cbSize", ctypes.wintypes.DWORD),            ("ClassGuid", GUID),            ("DevInst", ctypes.wintypes.DWORD),            ("Reserved", ctypes.c_void_p)            ]class SP_DEVICE_INTERFACE_DATA(ctypes.Structure):    _fields_ = [("cbSize", ctypes.wintypes.DWORD),            ("InterfaceClassGuid", GUID),            ("Flags", ctypes.wintypes.DWORD),            ("Reserved", ctypes.c_void_p)            ]class SP_DEVICE_INTERFACE_DETAIL_DATA(ctypes.Structure):    _fields_ = [("cbSize", ctypes.wintypes.DWORD),            ("DevicePath", ctypes.c_wchar*255)]GUID_DEVINTERFACE_VOLUME = GUID(0x53F5630D, 0xB6BF, 0x11D0,        (ctypes.c_ubyte*8)(0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B))hDevInfo = Nonedef get_class_devs():    global hDevInfo    hDevInfo = SetupDiGetClassDevs(ctypes.byref(GUID_DEVINTERFACE_VOLUME),                                   0,                                   0,                                   DIGCF_PRESENT | DIGCF_DEVICEINTERFACE)    if hDevInfo == INVALID_HANDLE_VALUE:        warn('get_class_devs', ctypes.windll.GetLastError(),             ctypes.windll.FormatError())def get_device_interface(i, device=None):    interfaceData = SP_DEVICE_INTERFACE_DATA()    interfaceData.cbSize = ctypes.sizeof(SP_DEVICE_INTERFACE_DATA)    if SetupDiEnumDeviceInterfaces(        hDevInfo,        device and ctypes.byref(device) or None,        ctypes.byref(GUID_DEVINTERFACE_VOLUME),        i,        ctypes.byref(interfaceData)):        return interfaceData    elif ctypes.GetLastError() == ERROR_NO_MORE_ITEMS:        return    else:        warn('get_device_interface', ctypes.GetLastError(),             ctypes.windll.FormatError())def get_device_interface_detail(interface):    detail = None    size = 0    length = ctypes.wintypes.DWORD(0)    device = SP_DEVINFO_DATA(cbSize=ctypes.sizeof(SP_DEVINFO_DATA))    while not SetupDiGetDeviceInterfaceDetail(        hDevInfo,        ctypes.byref(interface),        detail and ctypes.byref(detail) or None,        size,        ctypes.byref(length),        ctypes.byref(device)        ):        if ctypes.GetLastError() == ERROR_INSUFFICIENT_BUFFER:            size = length.value            detail = SP_DEVICE_INTERFACE_DETAIL_DATA(                cbSize=6)        else:            warn('get_device_interface_detail', ctypes.windll.GetLastError(),                 ctypes.windll.FormatError())            return    return detail.DevicePath, devicedef device_eject(devInst):    CM_Request_Device_Eject(devInst, None, None, 0, 0)def get_parent(devInst):    parent = ctypes.wintypes.DWORD(0)    CM_Get_Parent(ctypes.byref(parent), devInst, 0)    return parent.valuedef get_device_id(devInst):    buffer = ctypes.create_unicode_buffer(255)    CM_Get_Device_ID(devInst, ctypes.byref(buffer), 255, 0)    return buffer.valuedef get_volume_name(mount_point):    buffer = ctypes.create_unicode_buffer(50)    kernel32.GetVolumeNameForVolumeMountPointW(mount_point,                                               ctypes.byref(buffer), 50)    return buffer.valuedef get_path_name(volume):    buffer = ctypes.create_unicode_buffer(255)    length = ctypes.wintypes.DWORD(0)    kernel32.GetVolumePathNamesForVolumeNameW(volume, ctypes.byref(buffer),                                              255, ctypes.byref(length))    return buffer.valuedef connected_devices():    """    Returns a generator which returns small dictionaries of data    representing the connected USB storage devices.    """    get_class_devs() # reset the device class to pick up all devices    interface_index = 0    while True:        interface = get_device_interface(interface_index)        if interface is None:            break        interface_index += 1 # loop through the interfaces        path, device = get_device_interface_detail(interface)        device_id = get_device_id(device.DevInst)        if '_??_USBSTOR' in device_id:            # STORAGE\VOLUME\_??_USBSTOR#DISK&VEN_KINGSTON&PROD_DATATRAVELER_G3&REV_PMAP#00137            # 2982D6AEAC18576014E&0#{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}            reg_key = '\\'.join(device_id.split('_??_')[1].split('#')[:3])        else:            deviceParent = get_parent(device.DevInst)            reg_key = get_device_id(deviceParent)            if not reg_key.startswith('USBSTOR'):                # not a USB storage device                continue        volume_name = get_volume_name(path + '\\')        drive_name = get_path_name(volume_name)        with _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,                             'SYSTEM\\CurrentControlSet\\Enum\\%s' % reg_key) as k:            # pull the USB Name out of the registry            index = 0            friendly_name = None            while True:                try:                    name, value, type_ = _winreg.EnumValue(k, index)                except WindowsError:                    break                if name == 'FriendlyName':                    # blah blah USB Device                    friendly_name = value[:-len(' USB Device')]                    break                else:                    index += 1            if not friendly_name:                continue        yield {            'volume': volume_name,            'mount': drive_name,            'name': friendly_name,            }if __name__ == '__main__':    for d in connected_devices():        print d