diff options
Diffstat (limited to 'lib')
-rwxr-xr-x | lib/isodumper.py | 954 | ||||
-rwxr-xr-x | lib/raw_format.py | 52 |
2 files changed, 579 insertions, 427 deletions
diff --git a/lib/isodumper.py b/lib/isodumper.py index 8af078e..c62089b 100755 --- a/lib/isodumper.py +++ b/lib/isodumper.py @@ -1,4 +1,6 @@ -#!/usr/bin/python +#coding:utf-8 + +#!/usr/bin/python3 # # Copyright (c) 2007-2009 Canonical Ltd. # @@ -21,17 +23,35 @@ # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. -# Requires python-parted +# Requires python3-parted + +# ensure we're using the latest build, if called from our build environment +import sys +import imp + +sys.path.insert(0,'../../../build/swig/python3') +imp.reload(sys) +########### +# imports # +########### +import yui +#import locale +import time + +#################################### +# LOCALE (important for TERMINAL!) # +#################################### +# set the locale to de/utf-8 +#locale.setlocale(locale.LC_ALL, "") +#log = yui.YUILog.instance() +#log.setLogFileName("debug.log") +#log.enableDebugLogging( True ) -import gtk -import gtk.glade -import gobject import os, re import io import gettext from gettext import gettext as _ from subprocess import call, Popen, PIPE -import time import dbus @@ -55,6 +75,18 @@ class UDisks2(object): raise NoUDisks2() raise + def node_mountpoint(self,node): + + def de_mangle(raw): + return raw.replace('\\040', ' ').replace('\\011', '\t').replace('\\012', + '\n').replace('\\0134', '\\') + + for line in open('/proc/mounts').readlines(): + line = line.split() + if line[0] == node: + return de_mangle(line[1]) + return None + def device(self, device_node_path): device_node_path = os.path.realpath(device_node_path) devname = device_node_path.split('/')[-1] @@ -76,7 +108,7 @@ class UDisks2(object): devs = self.bus.get_object('org.freedesktop.UDisks2', '/org/freedesktop/UDisks2/block_devices') xml = devs.Introspect(dbus_interface='org.freedesktop.DBus.Introspectable') - for dev in re.finditer(r'name=[\'"](.+?)[\'"]', type(u'')(xml)): + for dev in re.finditer(r'name=[\'"](.+?)[\'"]', type('')(xml)): bd = self.bus.get_object('org.freedesktop.UDisks2', '/org/freedesktop/UDisks2/block_devices/%s2'%dev.group(1)) try: @@ -98,10 +130,10 @@ class UDisks2(object): re_drive = re.compile('(?P<path>.*?/drives/(?P<id>.*))') re_block = re.compile('(?P<path>.*?/block_devices/(?P<id>.*))') devs= [m.groupdict() for m in - [re_drive.match(path) for path in objects.keys()] + [re_drive.match(path) for path in (objects.keys())] if m] blocks = [m.groupdict() for m in - [re_block.match(path) for path in objects.keys()] + [re_block.match(path) for path in (objects.keys())] if m] list=[] @@ -120,194 +152,90 @@ class UDisks2(object): item.append(path) item.append(size) list.append(item) - self.device_nb=len(list) return list - def unmount(self, device_node_path): - d = self.device(device_node_path) - d.Unmount({'force':True, 'auth.no_user_interaction':True}, - dbus_interface=self.FILESYSTEM) - -class IsoDumper: - def __init__(self,user): - APP="isodumper" - DIR="/usr/share/locale" - RELEASE="v0.47" - - gettext.bindtextdomain(APP, DIR) - gettext.textdomain(APP) - gtk.glade.bindtextdomain(APP, DIR) - gtk.glade.textdomain(APP) - - # for the localisation of log file - self.user = user - - # get glade tree - self.gladefile = "/usr/share/isodumper/isodumper.glade" - self.wTree = gtk.glade.XML(self.gladefile) + def drive_for_device(self, device): + drive = device.Get(self.BLOCK, 'Drive', + dbus_interface='org.freedesktop.DBus.Properties') + return self.bus.get_object('org.freedesktop.UDisks2', drive) - # get globally needed widgets - self.window = self.wTree.get_widget("main_dialog") - self.devicelist = self.wTree.get_widget("device_combobox") - self.logview = self.wTree.get_widget("detail_text") - self.log = self.logview.get_buffer() - # set RELEASE number on title and About - self.window.set_title(self.window.get_title()+' '+RELEASE) - self.wTree.get_widget("about_dialog").set_version(RELEASE) + def eject(self, device_node_path): + drive = self.drive_for_device(self.device(device_node_path)) + drive.Eject({'auth.no_user_interaction':True}, + dbus_interface=self.DRIVE) - # define size of the selected device - self.deviceSize=0 - - # Operation running - self.operation=False - - # set default file filter to *.img - # Added for Mageia : *.iso - self.chooser = self.wTree.get_widget("filechooserbutton") - filt = gtk.FileFilter() - filt.add_pattern("*.iso") - filt.add_pattern("*.img") - self.chooser.set_filter(filt) - - - # optionnal backup of the device - self.backup_select = self.wTree.get_widget("backup_select") - self.backup_name = self.wTree.get_widget("backup_name") - self.backup_button = self.wTree.get_widget("backup_button") - self.choose = self.wTree.get_widget("choose") - self.backup_bname = self.wTree.get_widget("bname") - - - # set callbacks - dict = { "on_main_dialog_destroy_event" : self.confirm_close, - "on_main_dialog_delete_event" : self.confirm_close, - "on_cancel_button_clicked" : self.confirm_close, - "on_emergency_button_clicked" : self.restore, - "on_confirm_cancel_button_clicked": self.restore, - "on_filechooserbutton_file_set" : self.activate_devicelist, - "on_device_combobox_changed" : self.device_selected, - "on_nodev_close_clicked" : self.close, - "on_backup_button_clicked" : self.backup_go, - "on_backup_select_clicked" : self.backup_sel, - "on_select_clicked" : self.backup_choosed, - "on_about_button_clicked" : self.about, - "on_choose_cancel_clicked" : self.backup_cancel, - "on_format_button_clicked" : self.format_dialog, - "on_format_cancel_clicked" : self.format_cancel, - "on_format_go_clicked" : self.do_format, - "on_write_button_clicked" : self.do_write, - "on_help_close_clicked": self.help_close, - "on_help_clicked": self.help_dialog, - "on_update_button_clicked":self.update_list, - } - self.wTree.signal_autoconnect(dict) - - self.window.show_all() - # make sure we have a target device - self.u = None - try: - self.u = UDisks2() - except : - self.logger(_('UDisks2 is not available on your system')) - self.emergency() - self.get_devices() +class Info(object): + def __init__(self,title,richtext,text): + self.title=title + self.richtext=richtext + self.text=text - def update_list(self, widget): - for i in xrange(self.device_nb): - self.devicelist.remove_text(0) - self.get_devices() - self.restore(widget) + +class IsoDumper(object): def get_devices(self): - dialog = self.wTree.get_widget("nodev_dialog") self.list=self.u.find_devices() while len(self.list)==0: - exit_dialog=dialog.run() - if (exit_dialog==2) : - dialog.destroy() - exit(0) - self.list = self.u.find_devices() - for name, path, size in self.list: - if size != 0 : + if self.nodevDialog(): + self.list = self.u.find_devices() + else: + return False + break + self.devicelist.addItem("",False) + if len(self.list)>0: + for name, path, size in self.list: + if size != 0 : # convert in Mbytes - sizeM=str(int(size)/(1024*1024)) - self.devicelist.append_text(name+' ('+path.lstrip()+') '+sizeM+_('Mb')) - self.device_nb=len(self.list) - dialog.hide() - - def device_selected(self, widget): - self.dev = self.devicelist.get_active_text() - if self.dev != None: + sizeM=str(int(size)/(1024*1024)) + self.devicelist.addItem(str(name+' ('+path.lstrip()+') '+sizeM+_('Mb')),False) + return True + + + def update_list(self ): + self.devicelist.deleteAllItems() + self.get_devices() + self.img_name = "" + self.ima.setLabel(self.ChooseImage) + self.backup_select.setLabel(self.ChooseImage) + self.restore() + + def device_selected(self): + selitem = self.devicelist.selectedItem() + if selitem != None: + self.dev = selitem.label() for name, path, size in self.list: if self.dev.startswith(name): self.deviceSize=size self.device_name=name.rstrip().replace(' ', '') + self.logger(_('Target Device: ')+ self.dev) + self.formatbt.setEnabled() + self.ima.setEnabled() + self.backup_select.setEnabled() break - self.backup_select.set_sensitive(True) - self.wTree.get_widget("format_button").set_sensitive(True) - self.chooser.set_sensitive(True) - if self.chooser.get_current_folder_uri() == None : - self.chooser.set_current_folder_uri('file:///home/'+self.user) - self.logger(_('Target Device: ')+ self.dev) - - def backup_sel(self,widget): + + + def backup_sel(self): if self.backup_bname.get_current_folder_uri() == None : self.backup_bname.set_current_folder_uri('file:///home/'+self.user) self.backup_bname.set_current_name(self.device_name+".img") self.choose.run() - def backup_cancel(self,widget): - self.choose.hide() - # Unckeck the choice to backup - self.backup_button.set_sensitive(False) - - def backup_choosed(self, widget): - exit_dialog=self.backup_bname.get_filename() - if exit_dialog != None: - # Add .iso if not specified - if not exit_dialog.lower().endswith('.img'): - exit_dialog=exit_dialog+".img" - head, tail = os.path.split(exit_dialog) - self.backup_dest=exit_dialog - self.backup_select.set_label(tail) - self.backup_button.set_sensitive(True) - self.backup_select.set_tooltip_text(exit_dialog) - self.logger(_('Backup in: ')+ exit_dialog) - expander = self.wTree.get_widget("detail_expander") - expander.set_sensitive(True) - self.choose.hide() - - def format_dialog(self,widget): - self.backup_select.set_sensitive(False) - format_button=self.wTree.get_widget("format_button") - format_button.set_sensitive(False) - filechooserbutton=self.wTree.get_widget("filechooserbutton") - filechooserbutton.set_sensitive(False) - write_button = self.wTree.get_widget("write_button") - write_button.set_sensitive(False) - self.devicelist.set_sensitive(False) - dialog=self.wTree.get_widget("format") - self.wTree.get_widget("format_device").set_text(self.dev) - self.wTree.get_widget("format_name").set_text(self.dev.split('(')[0]) - exit_dialog=dialog.run() - if exit_dialog==0: - dialog.hide() - - def do_format(self, widget) : + def backup_choosed(self): + # Add .img if not specified + if not self.backup_img_name.lower().endswith('.img'): + self.backup_img_name=self.backup_img_name+".img" + head, tail = os.path.split(self.backup_img_name) + self.backup_dest=self.backup_img_name + self.backup_select.setLabel(tail) + self.backupbt.setEnabled() + #self.backup_select.set_tooltip_text(self.backup_img_name) + self.logger(_('Backup to: ')+ self.backup_img_name) + + def do_format(self,format_type,name) : target = self.dev.split('(')[1].split(')')[0] - dialog = self.wTree.get_widget("confirm_dialog") - expander = self.wTree.get_widget("detail_expander") - expander.set_sensitive(True) - resp = dialog.run() - dev_name=self.wTree.get_widget("format_name").get_text() - if resp: - dialog.hide() - if self.wTree.get_widget("format_fat").get_active(): - rc=self.raw_format(target, 'fat32', dev_name.upper()[:11]) - if self.wTree.get_widget("format_ntfs").get_active(): - rc=self.raw_format(target, 'ntfs', dev_name[:32]) - if self.wTree.get_widget("format_ext4").get_active(): - rc=self.raw_format(target, 'ext4', dev_name) + info = Info(_("Formatting confirmation"),True,self.warning) + if self.ask_YesOrNo(info): + rc=self.raw_format(target, format_type, name) self.operation=False if rc == 0: message = _('The device was formatted successfully.') @@ -316,39 +244,34 @@ class IsoDumper: elif rc == 5: message = _("An error occurred while creating a partition.") self.logger(message) - self.emergency() + self.emergency(message) elif rc == 127: message = _('Authentication error.') self.logger(message) - self.emergency() + self.emergency(message) else: message = _('An error occurred.') - self.emergency() - self.wTree.get_widget("format").hide() - self.backup_select.set_sensitive(True) - self.wTree.get_widget("format_button").set_sensitive(True) - self.wTree.get_widget("filechooserbutton").set_sensitive(True) - else: - dialog.hide() - - def restore(self,widget): - self.backup_select.set_sensitive(True) - self.wTree.get_widget("format_button").set_sensitive(True) - self.wTree.get_widget("filechooserbutton").set_sensitive(True) - self.devicelist.set_sensitive(True) - self.wTree.get_widget("emergency_dialog").hide() - progress = self.wTree.get_widget("progressbar") - progress.set_text("") - progress.set_fraction(0) - progress.set_sensitive(False) + self.emergency(message) + + def restore(self): + self.backup_select.setDisabled() + self.backupbt.setDisabled() + self.formatbt.setDisabled() + self.ima.setDisabled() + self.writebt.setDisabled() + self.devicelist.setEnabled() + self.progress.setLabel("") + self.progress.setValue(0) + self.progress.setDisabled() + self.refreshbt.setEnabled() def raw_format(self, usb_path, fstype, label): self.operation=True if os.geteuid() > 0: launcher='pkexec' - self.process = Popen([launcher,'/usr/bin/python', '-u', '/usr/lib/isodumper/raw_format.py','-d',usb_path,'-f',fstype, '-l', label, '-u', str(os.geteuid()), '-g', str(os.getgid())], shell=False, stdout=PIPE, preexec_fn=os.setsid) + self.process = Popen([launcher,'/usr/bin/python3', '-u', '/usr/lib/isodumper/raw_format.py','-d',usb_path,'-f',fstype, '-l', label, '-u', str(os.geteuid()), '-g', str(os.getgid())], shell=False, stdout=PIPE, preexec_fn=os.setsid) else: - self.process = Popen(['/usr/bin/python', '-u', '/usr/lib/isodumper/raw_format.py','-d',usb_path,'-f',fstype, '-l', label, '-u', str(os.geteuid()), '-g', str(os.getgid())], shell=False, stdout=PIPE, preexec_fn=os.setsid) + self.process = Popen(['/usr/bin/python3', '-u', '/usr/lib/isodumper/raw_format.py','-d',usb_path,'-f',fstype, '-l', label, '-u', str(os.geteuid()), '-g', str(os.getgid())], shell=False, stdout=PIPE, preexec_fn=os.setsid) working=True while working: time.sleep(0.5) @@ -361,300 +284,263 @@ class IsoDumper: working= False return rc - def format_cancel(self, widget): - dialog=self.wTree.get_widget("format") - dialog.hide() - self.backup_select.set_sensitive(True) - format_button=self.wTree.get_widget("format_button") - filechooserbutton=self.wTree.get_widget("filechooserbutton") - format_button.set_sensitive(True) - filechooserbutton.set_sensitive(True) - self.devicelist.set_sensitive(True) - - def backup_go(self,widget): - dest = self.backup_dest + def backup_go(self): + dest = self.backup_img_name if os.path.exists(dest): - dialog=self.wTree.get_widget("confirm_overwrite") - resp=dialog.run() - if resp !=-5: # GTK_RESPONSE_OK - dialog.hide() + info = Info(_("Backup confirmation"),True,_("Do you want to overwrite the file?")) + if not(self.ask_YesOrNo(info)): + self.returncode = 1 return True - else: - dialog.hide() - # check free space st = os.statvfs(os.path.dirname(dest)) free = st.f_bavail * st.f_frsize if free<self.deviceSize : sizeM=str(self.deviceSize/(1024*1024)) - self.logger(_("The destination directory is too small to receive the backup (%s Mb needed)")%(sizeM)) - self.emergency() + message=_("The destination directory is too small to receive the backup (%s Mb needed)")%(sizeM) + self.logger(message) + self.emergency(message) else: self.returncode=0 source = self.dev.split('(')[1].split(')')[0] - self.logger(_('Backup in:')+' '+dest) - task = self.raw_write(source, dest, self.deviceSize) - gobject.idle_add(task.next) - while gtk.events_pending(): - gtk.main_iteration(True) + self.logger(_('Backup to:')+' '+dest) + self.raw_write(source, dest, self.deviceSize) if self.returncode==0: self.success() + - def do_write(self, widget): + def do_write(self): self.returncode = 0 - write_button = self.wTree.get_widget("write_button") - write_button.set_sensitive(False) - combo = self.wTree.get_widget("device_combobox") - combo.set_sensitive(False) - format_button=self.wTree.get_widget("format_button") - format_button.set_sensitive(False) - backup_select=self.wTree.get_widget("backup_select") - backup_select.set_sensitive(False) - source = self.chooser.get_filename() + self.writebt.setDisabled() + self.devicelist.setDisabled() + self.formatbt.setDisabled() + self.backupbt.setDisabled() + self.backup_select.setDisabled() + self.progress.setEnabled() + source = self.img_name target = self.dev.split('(')[1].split(')')[0] - dialog = self.wTree.get_widget("confirm_dialog") - self.logger(_('Target Device: ')+self.dev) +# self.logger(_('Image: ')+source) +# self.logger(_('Target Device: ')+self.dev) b = os.path.getsize(source) if b > (self.deviceSize): - self.logger(_('The device is too small to contain the ISO file.')) - self.emergency() + message = _('The device is too small to contain the ISO file.') + self.logger(message) + self.emergency(message) else: - resp = dialog.run() - if resp: + info = Info(_("Writing confirmation"),True,self.warning) + if self.ask_YesOrNo(info): if self.deviceSize> 1024*1024*1024*32 : - message=self.wTree.get_widget("label1") - message.set_text(_('The device is bigger than 32 Gbytes. Are you sure you want use it?')) - resp = dialog.run() - if resp: + info = Info(_("Warning"),True,_('The device is bigger than 32 Gbytes. Are you sure you want use it?')) + if self.ask_YesOrNo(info): pass else: - self.emergency() - dialog.hide() + self.emergency(message) return - self.chooser.set_sensitive(False) + self.ima.setDisabled() + self.writebt.setDisabled() self.do_umount(target) - dialog.hide() if self.returncode != 1: # Writing step - #Dump mode + #Dump mode self.returncode=0 b=os.path.getsize(source) - task = self.raw_write(source, target, b) - gobject.idle_add(task.next) - while gtk.events_pending(): - gtk.main_iteration(True) - task = self.check_write(target, b) - gobject.idle_add(task.next) - while gtk.events_pending(): - gtk.main_iteration(True) + self.raw_write(source, target, b) if self.returncode == 0: + self.check_write(target, b) self.success() else: - self.restore(widget) + self.restore() else: - dialog.hide() - combo.set_sensitive(True) - write_button.set_sensitive(True) - format_button.set_sensitive(True) - backup_select.set_sensitive(True) + self.restore() def do_umount(self, target): mounts = self.get_mounted(target) if mounts: self.logger(_('Unmounting all partitions of ')+target+':') for mount in mounts: self.logger(_('Trying to unmount ')+mount[0]+'...') - while gtk.events_pending(): - gtk.main_iteration(True) try: retcode = call('umount '+mount[0], shell=True) if retcode == 32: message = _('Partition %s is busy')%mount[0] self.logger(message) - self.emergency() + self.emergency(message) elif retcode< 0: - self.logger(_('Error, umount ')+mount[0]+_(' was terminated by signal ')+str(retcode)) - self.emergency() + message = _('Error, umount ')+mount[0]+_(' was terminated by signal ')+str(retcode) + self.logger(message) + self.emergency(message) elif retcode == 0: self.logger(mount[0]+_(' successfully unmounted')) else: - self.logger(_('Error, umount ')+mount[0]+_(' returned ')+str(retcode)) - self.emergency() - except OSError, e: - self.logger(_('Execution failed: ')+str(e)) - self.emergency() + message = _('Error, umount ')+mount[0]+_(' returned ')+str(retcode) + self.logger(message) + self.emergency(message) + except OSError as e: + message = _('Execution failed: ')+str(e) + self.logger(message) + self.emergency(message) def get_mounted(self, target): try: lines = [line.strip("\n").split(" ") for line in open ("/etc/mtab", "r").readlines()] return [mount for mount in lines if mount[0].startswith(target)] except: - self.logger(_('Could not read mtab !')) - self.emergency() + message = _('Could not read mtab !') + self.logger(message) + self.emergency(message) def raw_write(self, source, target, b): self.operation=True - bs=4096*128 try: ifc=io.open(source, "rb",1) except: - self.logger(_('Reading error.')+ source) - self.emergency() + message = _('Reading error.')+ source + self.logger(message) + self.emergency(message) return else: try: ofc= io.open(target, 'wb',0) except: - self.logger(_('You have not the rights for writing on the device')) - self.emergency() - self.close('dummy') + message = _("You don't have permission to write to the device") +" "+ target + self.logger(message) + self.emergency(message) + self.close() else: - progress = self.wTree.get_widget("progressbar") - progress.set_sensitive(True) - progress.set_text(_('Writing ')+source.split('/')[-1]+_(' to ')+target.split('/')[-1]) + self.progress.setLabel(_('Writing ')+source.split('/')[-1]+_(' to ')+target.split('/')[-1]) self.logger(_('Executing copy from ')+source+_(' to ')+target) - while gtk.events_pending(): - gtk.main_iteration(True) - steps=range(0, b+1, b/100) + steps=list(range(0, b+1, int(b/100))) steps.append(b) indice=1 written=0 - ncuts=b/bs + ncuts=int(b/bs) while ncuts <= 100: - bs=bs/2 - ncuts=b/bs - for i in xrange(0,ncuts+1): + bs=int(bs/2) + ncuts=int(b/bs) + for i in range(0,int(ncuts)+1): try: buf=ifc.read(bs) except: - self.logger(_("Reading error.")) - self.emergency() + message = _("Reading error.") + self.logger(message) + self.emergency(message) return try: ofc.write(buf) except: - self.logger(_("Writing error.")) - self.emergency() + message = _("Writing error.") + self.logger(message) + self.emergency(message) return written+=len(buf) if written > steps[indice]: if indice%1==0: self.logger(_('Wrote: ')+str(indice)+'% '+str(written)+' bytes') - mark = self.log.create_mark("end", self.log.get_end_iter(), False) - self.logview.scroll_to_mark(mark, 0.05, True, 0.0, 1.0) - progress.set_fraction(float(indice)/100) - while gtk.events_pending(): - gtk.main_iteration(True) + self.progress.setValue(indice) + self.dialog.pollEvent() indice +=1 try: os.fsync(ofc) except: - self.logger(_("Writing error.")) - self.emergency() + message = _("Writing error.") + self.logger(message) + self.emergency(message) return - yield True - progress.set_fraction(1.0) + self.progress.setValue(100) self.logger(_('Image ')+source.split('/')[-1]+_(' successfully written to ')+target) self.logger(_('Bytes written: ')+str(written)) try: ofc.close() except: - self.logger(_("Writing error.")) - self.emergency() + message = _("Writing error.") + self.logger(message) + self.emergency(message) ifc.close() - yield False def check_write(self, target, b): import hashlib - progress = self.wTree.get_widget("progressbar") - progress.set_sensitive(True) - progress.set_text(_('Checking ')+target.split('/')[-1]) - progress.set_fraction(0.0) - steps=range(0, b+1, b/100) + self.progress.setEnabled() + self.progress.setLabel(_('Checking ')+target.split('/')[-1]) + self.progress.setValue(0) + steps=list(range(0, b+1, int(b/100))) steps.append(b) indice=0 checked=0 sha1func=hashlib.sha1() md5func=hashlib.md5() - ncuts=b/1024 + ncuts=int(b/1024) try: - with open(target, 'rb') as f: - for x in xrange(0,ncuts): - block = f.read(1024) - sha1func.update(block) - md5func.update(block) - if checked > steps[indice]: - progress.set_fraction(float(indice)/100) - indice +=1 - while gtk.events_pending(): - gtk.main_iteration(True) - yield True - checked+=1024 - block = f.read(b-ncuts*1024) - sha1func.update(block) - md5func.update(block) - sha1sumcalc=sha1func.hexdigest() - md5sumcalc=md5func.hexdigest() - self.logger(_('SHA1 sum: ')+sha1sumcalc) - self.logger(_('MD5 sum: ')+md5sumcalc) - mark = self.log.create_mark("end", self.log.get_end_iter(), False) - self.logview.scroll_to_mark(mark, 0.05, True, 0.0, 1.0) - f.close() - except: - pass - progress.set_fraction(1.0) - yield False + with open(target, 'rb') as f: + for x in range(0,ncuts): + block = f.read(1024) + sha1func.update(block) + md5func.update(block) + if checked > steps[indice]: + self.progress.setValue(indice) + self.dialog.pollEvent() + indice +=1 + checked+=1024 + block = f.read(b-ncuts*1024) + sha1func.update(block) + md5func.update(block) + sha1sumcalc=sha1func.hexdigest() + md5sumcalc=md5func.hexdigest() + self.logger(_('SHA1 sum: ')+sha1sumcalc) + self.logger(_('MD5 sum: ')+md5sumcalc) + f.close() + except: + pass + self.progress.setValue(100) def success(self): self.operation=False - dialog = self.wTree.get_widget("success_dialog") self.final_unsensitive() - resp = dialog.run() - if resp: - dialog.hide() + info = Info(_("Success"),True,_("The operation completed successfully.\n\ + You are free to unplug it now, a logfile \n\ +(/home/-user- or /root)/.isodumper/isodumper.log will be saved when\n\ + you close the application.")) + if self.ask_OK(info) : + return - def confirm_close(self, widget, *args): + def confirm_close(self, *args): if self.operation==False: # no writing , backup nor format running - self.close('dummy') + self.close() else: # writing , backup or format running - dialog=self.wTree.get_widget("Quit_warning") - resp = dialog.run() - if resp==-5 : # GTK_RESPONSE_OK - self.close('dummy') - else: - dialog.hide() + info = Info(_("Warning"),True,_("Writing is in progress. Exiting during writing \n\ + will make the device or the backup unusable.\n\ + Are you sure you want to quit during writing?")) + if self.ask_YesOrNo(info) : return True + else: + return False - def emergency(self): + def emergency(self,message): self.operation=False self.returncode=1 self.final_unsensitive() - dialog = self.wTree.get_widget("emergency_dialog") - expander = self.wTree.get_widget("detail_expander") - expander.set_expanded(True) - mark = self.log.create_mark("end", self.log.get_end_iter(), False) - self.logview.scroll_to_mark(mark, 0.05, True, 0.0, 1.0) - resp = dialog.run() - if resp: - dialog.hide() + info = Info(_("Error"),True,message) + self.ask_OK(info) def final_unsensitive(self): - self.chooser.set_sensitive(False) - self.devicelist.set_sensitive(False) - write_button = self.wTree.get_widget("write_button") - write_button.set_sensitive(False) - progress = self.wTree.get_widget("progressbar") - progress.set_sensitive(False) - self.backup_select.set_sensitive(False) - - def close(self, widget): + self.ima.setDisabled() + self.devicelist.setDisabled() + self.writebt.setDisabled() + self.progress.setDisabled() + self.backup_select.setDisabled() + + def wip_unsensitive(self): + self.ima.setDisabled() + self.devicelist.setDisabled() + self.writebt.setDisabled() + self.backup_select.setDisabled() + self.backupbt.setDisabled() + self.refreshbt.setDisabled() + + def close(self): self.write_logfile() - gtk.main_quit() - exit(0) + self.dialog.destroy() + #exit(0) def write_logfile(self): - start = self.log.get_start_iter() - end = self.log.get_end_iter() import pwd pw = pwd.getpwnam(self.user) uid = pw.pw_uid @@ -667,45 +553,311 @@ class IsoDumper: os.mkdir(logpath) else: logpath='/root' - logfile=open(logpath+'/isodumper.log',"w") - logfile.write(self.log.get_text(start, end, False)) + logfile=open(logpath+'/isodumper.log',"w", encoding="utf-8") + logfile.write(self.logview.logText()) logfile.close() - print self.log.get_text(start, end, False) + print((self.logview.logText())) def logger(self, text): - self.log.insert_at_cursor(text+"\n") - - def activate_devicelist(self, widget): - expander = self.wTree.get_widget("detail_expander") - expander.set_sensitive(True) - self.img_name = self.chooser.get_filename() - write_button = self.wTree.get_widget("write_button") - write_button.set_sensitive(True) + self.logview.appendLines(text+"\n") + + def activate_devicelist(self): + self.devicelist.setEnabled() self.logger(_('Image ')+": "+ self.img_name) - self.chooser.set_tooltip_text(self.img_name) +# self.chooser.set_tooltip_text(self.img_name) + + def help_dialog(self): + info = Info(_("IsoDumper"),True,_("Mageia IsoDumper<BR />\ +----------------<BR />\ +This GUI program is primarily for safely writing a bootable ISO image to a USB flash drive, \ +an operation devious & potentially hazardous when done by hand. As a bonus, it can also back up the\ +entire previous<BR />contents of the flash drive onto the hard disc, and restore the flash drive \ +to its previous state subsequently.<BR />\ +It gives also a feature for formatting the USB device.<BR />\ +<BR />\ +IsoDumper can be launched either from the menus, or a user or root console with the command 'isodumper'.<BR />\ +For normal users, the root password is solicited; this is necessary for the program's operation. <BR />\ +The flash drive can be inserted beforehand or once the program is started. In the latter case, a \ +dialogue will say that there is no flash drive inserted, and allow a 'retry' to find it once it is. <BR />\ +(You may have to close any automatically opened File Manager window).<BR />\ +<BR />\ +The fields of the main window are as follows:<BR />\ +- Device to work on: the device of the USB flash drive, a drop-down list to choose from.<BR />\ +- Write Image: to choose the source ISO image *.iso (or flash drive backup file *.img) to write out.<BR />\ +- Write to device: This button launches the operation - with a prior warning dialogue. <BR />\ +The operation is shown in the progress bar beneath.<BR />\ +- Backup to: define the name and placement of the backup image file. The current flash drive \ +will be backed up to a disc file. Note that the entire flash drive is preserved, regardless of its \ +actual contents; ensure that you have the necessary free disc space (the same size as the USB device). \ +This backup file can be used later to restore the flash drive by selecting it as the source *.img file to write out.<BR />\ +- Backup the device: launch the backup operation.<BR />\ +- Format the device: create an unique partition on the entire volume in the specified format in FAT, \ +NTFS or ext. You can specify a volume name and the format in a new dialog box.<BR />")) + if self.ask_OK(info) : + return - def activate_backup(self, widget): - self.backup_img_name = self.backup_dir.get_filename() + def __init__(self,user): + APP="isodumper" + DIR="/usr/share/locale" + self.RELEASE="v0.51" - def help_dialog(self, widget): - dialog = self.wTree.get_widget("help_dialog") - dialog.run() + gettext.bindtextdomain(APP, DIR) + gettext.textdomain(APP) - def help_close(self, widget): - dialog = self.wTree.get_widget("help_dialog") - dialog.hide() + # for the localisation of log file + self.user = user - def about(self, widget): - about_button = self.wTree.get_widget("about_button") - about_button.set_sensitive(True) - dialog = self.wTree.get_widget("about_dialog") - resp = dialog.run() - if resp: - dialog.hide() + # define size of the selected device + self.deviceSize=0 + + # Operation running + self.operation=False + + self.ChooseImage = _("Choose an image") + self.warning = _("Warning\nThis will destroy all data on the target device,\n\ + are you sure you want to proceed?\n\ + If you say ok here, please <b>do not unplug</b>\ + the device during the following operation.") + """ + Init/Constructor for the 'widgets' + """ + yui.YUI.app().setApplicationTitle(_("IsoDumper")+" "+self.RELEASE) + yui.YUI.app().setApplicationIcon("/usr/share/icons/isodumper.png") + self.atelier = yui.YUI.widgetFactory() + self.dialog = self.atelier.createPopupDialog() + # create the main gui + # +---+-----------------+ + # + banner + + # +---+-----------------+ + # | devicelist | + # +---+-----+------+----+ + # + L | ima | writebt | + # +---+-----+------+----+ + # + L | backup_select | backupbt | + # +---+-----+------+----+ + # + F | formatbt | + # +----------------+----+ + # | progress | + # +---------------------+ + # | report | + # +---------------------+ + # | refreshbt | aboutbt | helpbt | quitbt | + # +---------------------+ + self.ancrage = self.atelier.createReplacePoint(self.dialog) + self.box = self.atelier.createVBox(self.ancrage) + self.bannerbox = self.atelier.createHBox(self.box) + self.banner=self.atelier.createImage(self.bannerbox,"/usr/share/isodumper/header.svg") + self.devicebox = self.atelier.createHBox(self.box) + self.devicebox.setWeight(1,10) + self.devicelist=self.atelier.createComboBox(self.devicebox,_("Device to work on:"),False) + self.devicelist.setNotify() + self.devicelist.setStretchable(0,True) + self.writebox = self.atelier.createHBox(self.box) + self.atelier.createLabel(self.writebox,_("Write Image:")) + # add file picker for image file + self.ima=self.atelier.createPushButton(self.writebox,self.ChooseImage) + self.ima.setStretchable(0,True) + self.ima.setDisabled() + self.atelier.createHStretch(self.writebox) + self.writebt = self.atelier.createPushButton(self.writebox, _("&Write to device" )) + self.writebt.setDisabled() + self.backupbox = self.atelier.createHBox(self.box) + self.atelier.createLabel(self.backupbox,_("Backup to:")) + # add file picker for backup file name + self.backup_select=self.atelier.createPushButton(self.backupbox,self.ChooseImage) + self.backup_select.setStretchable(0,True) + self.backup_select.setDisabled() + self.atelier.createHStretch(self.backupbox) + self.backupbt = self.atelier.createPushButton(self.backupbox, _("&Backup the device" )) + self.backupbt.setDisabled() + self.formatbox = self.atelier.createHBox(self.box) + #self.formatbox.setWeight(1,10) + self.atelier.createLabel(self.formatbox,_("Format the device in FAT, NTFS or ext:")) + self.atelier.createHStretch(self.formatbox) + self.formatbt = self.atelier.createPushButton(self.formatbox, _("&Format the device" )) + self.formatbt.setDisabled() + self.progressbox = self.atelier.createHBox(self.box) + self.progressbox.setWeight(1,10) + self.progress = self.atelier.createProgressBar(self.progressbox,_("Progression"),100) + self.progress.setStretchable(0,True) + self.reportbox = self.atelier.createHBox(self.box) + #self.reportbox.setWeight(1,10) + self.logview = self.atelier.createLogView(self.reportbox,_("Report"), 10) + self.logview.setStretchable(0,True) + #self.reportbox.setWeight(1,20) + self.buttonsbox = self.atelier.createHBox(self.box) + #self.buttonsbox.setWeight(1,10) + self.refreshbt = self.atelier.createPushButton(self.buttonsbox, _("&Refresh" )) + self.refreshbt.setStretchable(0,True) + self.aboutbt = self.atelier.createPushButton(self.buttonsbox, _("&About" )) + self.aboutbt.setStretchable(0,True) + self.helpbt = self.atelier.createPushButton(self.buttonsbox, _("&Help" )) + self.helpbt.setStretchable(0,True) + self.quitbt = self.atelier.createPushButton(self.buttonsbox, _("&Quit" )) + self.quitbt.setStretchable(0,True) + self.u = None + try: + self.u = UDisks2() + except : + message = _('UDisks2 is not available on your system') + self.logger(message) + self.emergency(message) + if not self.get_devices(): + self.dialog.destroy() + self.device_selected() + self.dialog.recalcLayout() + self.ancrage.showChild() + + def ask_format(self): + self.ima.setDisabled() + self.formatbt.setDisabled() + self.backup_select.setDisabled() + self.writebt.setDisabled() + self.devicelist.setDisabled() + atelier = yui.YUI.widgetFactory() + dialog = atelier.createPopupDialog() +# dialog.setTitle(_("Choose format")) + vb=atelier.createVBox(dialog) + label = atelier.createInputField(vb,_("Label for the device:")) + cr = atelier.createRadioButtonGroup(vb) + vb_c = atelier.createVBox(cr) + vb_c1 = atelier.createHBox(vb_c) + format_fat = atelier.createRadioButton(atelier.createLeft(vb_c1),_("FAT 32 (Windows)")) + vb_c2 = atelier.createHBox(vb_c) + format_ntfs = atelier.createRadioButton(atelier.createLeft(vb_c2),_("NTFS (Windows)")) + vb_c3 = atelier.createHBox(vb_c) + format_ext = atelier.createRadioButton(atelier.createLeft(vb_c3),_("ext4 (Linux)")) + bb = atelier.createHBox(vb) + executebt = atelier.createPushButton(bb,_("Execute")) + cancelbt = atelier.createPushButton(bb,_("Cancel")) + dialog.open() + returncode = True + while True: + event = dialog.waitForEvent() + if event.eventType() == yui.YEvent.CancelEvent: + returncode = False + break + if event.widget() == executebt: + if format_fat.value(): + format_type = 'fat32' + format_label = label.value().upper()[:11] + break + if format_ntfs.value(): + format_type = 'ntfs' + format_label = label.value()[:32] + break + if format_ext.value(): + format_type = 'ext4' + format_label = label.value() + break + if event.widget() == cancelbt: + self.restore() + returncode = False + break + dialog.destroy() + if returncode: + return True,format_type,format_label + else: + return False," "," " + + + def ask_OK(self, info): + yui.YUI.widgetFactory + mgafactory = yui.YMGAWidgetFactory.getYMGAWidgetFactory(yui.YExternalWidgets.externalWidgetFactory("mga")) + dlg = mgafactory.createDialogBox(yui.YMGAMessageBox.B_ONE) + dlg.setTitle(info.title) + dlg.setText(info.text, info.richtext) + dlg.setButtonLabel("OK", yui.YMGAMessageBox.B_ONE) + dlg.setMinSize(60, 10); + return dlg.show() == yui.YMGAMessageBox.B_ONE + + def ask_YesOrNo(self, info): + yui.YUI.widgetFactory + mgafactory = yui.YMGAWidgetFactory.getYMGAWidgetFactory(yui.YExternalWidgets.externalWidgetFactory("mga")) + dlg = mgafactory.createDialogBox(yui.YMGAMessageBox.B_TWO) + dlg.setTitle(info.title) + dlg.setText(info.text, info.richtext) + dlg.setButtonLabel("Yes", yui.YMGAMessageBox.B_ONE) + dlg.setButtonLabel("No", yui.YMGAMessageBox.B_TWO) + dlg.setMinSize(60, 8); + return dlg.show() == yui.YMGAMessageBox.B_ONE + + def aboutDialog(self): + yui.YUI.widgetFactory; + mgafactory = yui.YMGAWidgetFactory.getYMGAWidgetFactory(yui.YExternalWidgets.externalWidgetFactory("mga")) + dlg = mgafactory.createAboutDialog("Isodumper", self.RELEASE, "GPLv2", + "Oliver Grawert<BR />Papoteur<BR />Pictures : Thimotée Giet", _("A tool for writing ISO images to a device"), "") + dlg.show(); + + def nodevDialog(self): + yui.YUI.widgetFactory + mgafactory = yui.YMGAWidgetFactory.getYMGAWidgetFactory(yui.YExternalWidgets.externalWidgetFactory("mga")) + dlg = mgafactory.createDialogBox(yui.YMGAMessageBox.B_TWO) + dlg.setTitle("IsoDumper") + dlg.setText(_("Warning\nNo target devices were found.\nYou need to plug in a USB Key to which the image can be written.")) + dlg.setButtonLabel(_("&Refresh"), yui.YMGAMessageBox.B_ONE) + dlg.setButtonLabel(_("Cancel"), yui.YMGAMessageBox.B_TWO) + dlg.setMinSize(60, 8); + return dlg.show() == yui.YMGAMessageBox.B_ONE + + def handleevent(self): + self.traitement=None + while True: + event = self.dialog.waitForEvent() + if event.eventType() == yui.YEvent.CancelEvent: + self.close() + break + if event.widget() == self.quitbt: + self.close() + break + if event.widget() == self.ima: + self.img_name=yui.YUI.app().askForExistingFile('file:///home/'+self.user,"*.iso *.img","Choose an image") + self.ima.setLabel(self.img_name) + self.writebt.setEnabled() + self.activate_devicelist() + if event.widget() == self.writebt: + self.wip_unsensitive() + self.do_write() + self.restore() + if event.widget() == self.backupbt: + self.wip_unsensitive() + self.backup_go() + self.restore() + if event.widget() == self.backup_select: + self.backup_img_name=yui.YUI.app().askForSaveFileName('file:///home/'+self.user,"*.img","Backup to:") + if self.backup_img_name != '': + self.backup_choosed() + if event.widget() == self.formatbt: + self.wip_unsensitive() + code,format_type,name = self.ask_format() + if code: + self.do_format(format_type,name) + self.restore() + if event.widget() == self.devicelist: + self.device_selected() + try: + if event.widget() == self.refreshbt: + self.update_list() + except: + pass + try: + if event.widget() == self.helpbt: + self.help_dialog() + except: + pass + try: + if event.widget() == self.quitbt: + self.confirm_close() + except: + pass + if event.widget() == self.aboutbt: + self.aboutDialog() if __name__ == "__main__": import sys user=sys.argv[1] app = IsoDumper(user) - gtk.main() + app.handleevent() + + diff --git a/lib/raw_format.py b/lib/raw_format.py index b634470..0cce0e9 100755 --- a/lib/raw_format.py +++ b/lib/raw_format.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python3 # # imported from project Mintstick, by Clement Lefebvre # https://github.com/linuxmint/mintstick/ @@ -24,7 +24,7 @@ import os, sys import getopt -import parted + from subprocess import call sys.path.append('/usr/lib/isodumper') @@ -32,22 +32,22 @@ sys.path.append('/usr/lib/isodumper') def do_umount(target): mounts = get_mounted(target) if mounts: - print 'Unmounting all partitions of '+target+':' + print('Unmounting all partitions of '+target+':') for mount in mounts: - print 'Trying to unmount '+mount[0]+'...' + print('Trying to unmount '+mount[0]+'...') try: retcode = call('umount '+mount[0], shell=True) if retcode < 0: - print 'Error, umount '+mount[0]+' was terminated by signal '+str(retcode) + print('Error, umount '+mount[0]+' was terminated by signal '+str(retcode)) sys.exit(6) else: if retcode == 0: - print mount[0]+' successfully unmounted' + print(mount[0]+' successfully unmounted') else: - print 'Error, umount '+mount[0]+' returned '+str(retcode) + print('Error, umount '+mount[0]+' returned '+str(retcode)) sys.exit(6) - except OSError, e: - print 'Execution failed: '+str(e) + except OSError as e: + print('Execution failed: '+str(e)) sys.exit(6) @@ -56,11 +56,11 @@ def get_mounted(target): lines = [line.strip("\n").split(" ") for line in open ("/etc/mtab", "r").readlines()] return [mount for mount in lines if mount[0].startswith(target)] except: - print 'Could not read mtab !' + print('Could not read mtab !') sys.exit(6) def raw_format(device_path, fstype, volume_label, uid, gid): - + import parted do_umount(device_path) # First erase MBR and partition table , if any @@ -74,7 +74,7 @@ def raw_format(device_path, fstype, volume_label, uid, gid): disk.commit() except: # Unable to write the new partition - print "Can't create partition. The device could be read-only." + print("Can't create partition. The device could be read-only.") sys.exit(5) regions = disk.getFreeSpaceRegions() @@ -93,7 +93,7 @@ def raw_format(device_path, fstype, volume_label, uid, gid): try: geometry = parted.Geometry(device=device, start=start, end=end) except: - print "Geometry error - Can't create partition" + print("Geometry error - Can't create partition") sys.exit(5) # fstype @@ -122,26 +122,26 @@ def main(): # parse command line options try: opts, args = getopt.getopt(sys.argv[1:], "hd:f:l:u:g:", ["help", "device=","filesystem=","label=","uid=","gid="]) - except getopt.error, msg: - print msg - print "for help use --help" + except getopt.error as msg: + print(msg) + print("for help use --help") sys.exit(2) for o, a in opts: if o in ("-h", "--help"): - print "Usage: %s -d device -f filesystem -l volume_label\n" % sys.argv[0] - print "-d|--device : device path" - print "-f|--filesystem : filesystem\n" - print "-l|--label : volume label\n" - print "-u|--uid : uid of user\n" - print "-g|--gid : gid of user\n" - print "Example : %s -d /dev/sdj -f fat32 -l \"USB Stick\" -u 1000 -g 1000" % sys.argv[0] + print("Usage: %s -d device -f filesystem -l volume_label\n" % sys.argv[0]) + print("-d|--device : device path") + print("-f|--filesystem : filesystem\n") + print("-l|--label : volume label\n") + print("-u|--uid : uid of user\n") + print("-g|--gid : gid of user\n") + print("Example : %s -d /dev/sdj -f fat32 -l \"USB Stick\" -u 1000 -g 1000" % sys.argv[0]) sys.exit(0) elif o in ("-d"): device = a elif o in ("-f"): if a not in [ "fat32", "ntfs", "ext4" ]: - print "Specify fat32, ntfs or ext4" + print("Specify fat32, ntfs or ext4") sys.exit(3) fstype = a elif o in ("-l"): @@ -153,8 +153,8 @@ def main(): argc = len(sys.argv) if argc < 11: - print "Too few arguments" - print "for help use --help" + print("Too few arguments") + print("for help use --help") exit(2) raw_format(device, fstype, label, uid, gid) |