From 8a61e162447e24aeb10a621f59d28d923c43a25b Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 18 Jan 2016 10:05:28 +0530 Subject: [PATCH] Use full storage number for eject as well Makes it more robust and a simpler implementation --- src/calibre/devices/winusb.py | 44 ++++++++++++++++------------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/src/calibre/devices/winusb.py b/src/calibre/devices/winusb.py index 141613f84e..1a6ac7e456 100644 --- a/src/calibre/devices/winusb.py +++ b/src/calibre/devices/winusb.py @@ -573,7 +573,7 @@ def get_drive_letters_for_device(vendor_id, product_id, bcd=None, storage_number devid = 'Unknown' try: storage_number = get_storage_number(devpath) - except Exception as err: + except WindowsError as err: if debug: prints('Failed to get storage number for: %s with error: %s' % (devid, as_unicode(err))) continue @@ -641,39 +641,35 @@ def is_usb_device_connected(vendor_id, product_id): # {{{ def eject_drive(drive_letter): # {{{ drive_letter = type('')(drive_letter)[0] volume_access_path = '\\\\.\\' + drive_letter + ':' - devinst = devinst_from_device_number(drive_letter, get_storage_number(volume_access_path).number) - if devinst is None: - raise ValueError('Could not find device instance number from drive letter: %s' % drive_letter) + try: + sn = get_storage_number(volume_access_path)[:2] + except WindowsError: + return True + for devinfo, devpath in DeviceSet(guid=GUID_DEVINTERFACE_DISK).interfaces(ignore_errors=True): + try: + dsn = get_storage_number(devpath)[:2] + except WindowsError: + continue + if dsn == sn: + break + else: + return False + parent = DEVINST(0) - CM_Get_Parent(byref(parent), devinst, 0) + CM_Get_Parent(byref(parent), devinfo.DevInst, 0) max_tries = 3 while max_tries >= 0: max_tries -= 1 try: CM_Request_Device_Eject(parent, None, None, 0, 0) except WindowsError: + if max_tries < 0: + raise time.sleep(0.5) continue - return - raise ValueError('Failed to eject drive %s after three tries' % drive_letter) + return True + return False -def devinst_from_device_number(drive_letter, device_number): - drive_root = drive_letter + ':' + os.sep - buf = create_unicode_buffer(512) - drive_type = GetDriveType(drive_root) - QueryDosDevice(drive_letter + ':', buf, len(buf)) - is_floppy = '\\floppy' in buf.value.lower() - if drive_type == DRIVE_REMOVABLE: - guid = GUID_DEVINTERFACE_FLOPPY if is_floppy else GUID_DEVINTERFACE_DISK - elif drive_type == DRIVE_FIXED: - guid = GUID_DEVINTERFACE_DISK - elif drive_type == DRIVE_CDROM: - guid = GUID_DEVINTERFACE_CDROM - else: - raise ValueError('Unknown drive_type: %d' % drive_type) - for devinfo, devpath in DeviceSet(guid=guid).interfaces(ignore_errors=True): - if get_storage_number(devpath).number == device_number: - return devinfo.DevInst # }}} def develop(vendor_id=0x1949, product_id=0x4, bcd=None, do_eject=False): # {{{