%PDF- %PDF-
Direktori : /usr/lib/python3/dist-packages/usbcreator/backends/udisks/ |
Current File : //usr/lib/python3/dist-packages/usbcreator/backends/udisks/backend.py |
import dbus import logging import os import subprocess import tempfile from dbus.mainloop.glib import DBusGMainLoop, threads_init import gi gi.require_version('UDisks', '2.0') from gi.repository import Gio, GLib, UDisks from usbcreator.backends.base import Backend from usbcreator import misc loop_prefix = '/org/freedesktop/UDisks2/block_devices/loop' not_interesting = ( '/org/freedesktop/UDisks2/block_devices/dm_', '/org/freedesktop/UDisks2/block_devices/ram', '/org/freedesktop/UDisks2/block_devices/zram', '/org/freedesktop/UDisks2/drives/', ) import time class UDisksBackend(Backend): def __init__(self, allow_system_internal=False, bus=None): Backend.__init__(self) self.handles = [] self.allow_system_internal = allow_system_internal logging.debug('UDisks2Backend') DBusGMainLoop(set_as_default=True) threads_init() if bus: self.bus = bus else: self.bus = dbus.SystemBus() self.udisks = UDisks.Client.new_sync(None) self.helper = self.bus.get_object('com.ubuntu.USBCreator', '/com/ubuntu/USBCreator') self.helper = dbus.Interface(self.helper, 'com.ubuntu.USBCreator') self.helper.connect_to_signal('Progress', self.got_progress) self.no_options = GLib.Variant('a{sv}', {}) # Adapted from udisk's test harness. # This is why the entire backend needs to be its own thread. def retry_mount(self, fs): '''Try to mount until it does not fail with "Busy".''' timeout = 10 while timeout >= 0: try: return fs.call_mount_sync(self.no_options, None) except GLib.GError as e: if not 'UDisks2.Error.DeviceBusy' in e.message: raise logging.debug('Busy.') time.sleep(0.3) timeout -= 1 return '' def got_progress(self, complete): self.install_progress_cb(complete) # Device detection and processing functions. def detect_devices(self): '''Start looking for new devices to add. Devices added will be sent to the fronted using frontend.device_added. Devices will only be added as they arrive if a main loop is present.''' logging.debug('detect_devices') # TODO connect add/remove objects + changed interface signals self.manager = self.udisks.get_object_manager() self.handles += [self.manager.connect('object-added', lambda man, obj: self._udisks_obj_added(obj))] self.handles += [self.manager.connect('object-removed', lambda man, obj: self._device_removed(obj.get_object_path()))] self.handles += [self.manager.connect('interface-added', lambda man, obj, iface: self._device_changed(obj))] self.handles += [self.manager.connect('interface-removed', lambda man, obj, iface: self._device_changed(obj))] self.handles += [self.manager.connect('interface-proxy-properties-changed', lambda man, obj, iface, props, invalid: self._device_changed(obj))] for obj in self.manager.get_objects(): self._udisks_obj_added(obj) def _udisks_obj_added(self, obj): path = obj.get_object_path() for boring in not_interesting: if path.startswith(boring): return block = obj.get_block() if not block: return drive_name = block.get_cached_property('Drive').get_string() if drive_name != '/': drive = self.udisks.get_object(drive_name).get_drive() else: drive = None if drive and drive.get_cached_property('Optical').get_boolean(): return part = obj.get_partition() is_system = block.get_cached_property('HintSystem').get_boolean() is_loop = path.startswith(loop_prefix) if self.allow_system_internal or not (is_system or is_loop): if part: return else: self._udisks_drive_added(obj, block, drive, path) def _udisks_drive_added(self, obj, block, drive, path): logging.debug('drive added: %s' % path) if drive: vendor = drive.get_cached_property('Vendor').get_string() model = drive.get_cached_property('Model').get_string() size = block.get_cached_property('Size').get_uint64() label = block.get_cached_property('IdLabel').get_string() else: vendor = '' model = '' size = block.get_cached_property('Size').get_uint64() label = block.get_cached_property('IdLabel').get_string() if size <= 0: logging.debug('not adding device: 0 byte disk.') return self.targets[path] = { 'vendor': vendor, 'model' : model, 'label' : label, 'free' : -1, 'device': block.get_cached_property('Device').get_bytestring().decode('utf-8'), 'capacity' : size, 'status' : misc.NEED_FORMAT, 'mountpoint' : None, 'parent' : None, } if misc.callable(self.target_added_cb): self.target_added_cb(path) self.update_free() def _device_changed(self, obj): path = obj.get_object_path() logging.debug('device change %s' % path) # As this will happen in the same event, the frontend wont change # (though it needs to make sure the list is sorted, otherwise it will). self._device_removed(path) self._udisks_obj_added(obj) # Device manipulation functions. def _is_casper_cd(self, filename): tmpfile = tempfile.mkstemp()[1] for search in ['/.disk/info', '/.disk/mini-info']: cmd = ['osirrox', '-dev', filename, '-extract', search, tmpfile] subprocess.run(cmd, stderr=None, stdout=None) if os.stat(tmpfile).st_size > 0: f = open(tmpfile) output = f.read() f.close() os.unlink(tmpfile) return output return None def install(self, source, target, allow_system_internal=False): # TODO evand 2009-07-31: Lock source and target. logging.debug('install source: %s' % source) logging.debug('install target: %s' % target) # There's no going back now... for handle in self.handles: self.manager.disconnect(handle) dev = self.targets[target]['device'] Backend.install(self, source, target, device=dev, allow_system_internal=allow_system_internal) def cancel_install(self): Backend.cancel_install(self) def shutdown(self): try: self.helper.Shutdown() except GLib.GError as e: logging.exception('Could not shut down the dbus service.')