def __init__(self, image_folder, target_device, status_callback, partitions=None, expand=2): # expand -> 0 Expande a ultima particao # -> 1 Formata a ultima particao # -> 2 Nenhuma operacao (ele aplica a imagem e nao faz mais nada) # -> 3 Ele nao aplica a ultima particao assert check_if_root(), "You need to run this application as root" self.image_path = adjust_path(image_folder) self.target_device = target_device self.notify_status = status_callback self.partitions = partitions self.expand = expand self.timer = Timer(self.notify_percent) self.total_blocks = 0 self.processed_blocks = 0 self.current_percent = -1 self.active = False self.canceled = False if not os.path.isdir(self.image_path): log.info("The folder is invalid") self.notify_status("invalid_folder", \ {"invalid_folder":self.image_path}) raise InvalidFolder("Invalid folder {0}".format(output_folder))
def stop(self): if self.active: if hasattr(self, "buffer_manager"): self.buffer_manager.stop() self.active = False self.timer.stop() log.info("Create image stopped")
def mount_partition(device, folder = None): ''' Monta a particao recebida.(Ex.: /dev/sda1) Caso 'folder' nao tenha um destino valido, a particao eh montada em uma pasta temporaria ''' mount_device = None if folder is None: tmpd = make_temp_dir() else: tmpd = folder if device is None: log.error("No device given") return False output,erro,ret = run_simple_command_echo("mount {0} {1} {2}".format(MOUNT_OPTIONS, device, tmpd),True) if "already" in erro: log.error("{0} is arealdy exclusively mounted.".format(mount_device)) log.info("Trying to umount device above, and re-run") umount_real(mount_device) output,erro,ret = run_simple_command_echo("mount {0} {1} {2}".format(MOUNT_OPTIONS, mount_device, tmpd),True) if ret is not 0: log.error("{0}".format(erro)) #raise ErrorMountingFilesystem if folder is not None: mounted_devices.insert(0, folder) else: mounted_devices.append(tmpd) return tmpd
def stop(self): # When restoring only a swap partition, buffer_manager # isnt necessary if self.active and hasattr(self, "buffer_manager"): self.buffer_manager.stop() self.active = False self.timer.stop() log.info("Restore image stopped")
def chroot(root): real_root = os.open("/", os.O_RDONLY) mount_device("dev",root) mount_device("sys",root) mount_device("proc",root) os.chdir(root) log.info("chroot {0}".format(root)) os.chroot(root) return "/",real_root
def expand_last_partition(self): # After all data is copied to the disk # we instance class again to reload sync() device = Device(self.target_device) disk = Disk(device) partition = disk.get_last_partition() if partition is not None: if partition.type == PARTITION_NORMAL: log.info("Expanding {0} filesystem".\ format(partition.get_path())) self.notify_status("expand", {"device": partition.get_path()}) partition.filesystem.resize()
def run_simple_command_echo(cmd, echo=False): ''' run a given command returns the output, errors (if any) and returncode ''' if echo: log.info("{0}".format(cmd)) p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE) p.wait() output, err = p.communicate() ret = p.returncode return output,err,ret
def __init__(self, source_device, output_folder, status_callback, image_name="image", compressor_level=6, raw=False, split_size=0, create_iso=False, fill_with_zeros=False): self.image_name = image_name self.device_path = source_device self.target_path = adjust_path(output_folder) self.notify_status = status_callback self.compressor_level = compressor_level self.raw = raw self.split_size = split_size self.create_iso = create_iso self.fill_with_zeros = fill_with_zeros self.timer = Timer(self.notify_percent) self.total_blocks = 0 self.processed_blocks = 0 self.current_percent = -1 self.active = False self.canceled = False self.partclone_stderr = None self.partclone_sucess = False self.data_is_eof = False if not check_if_root(): log.info("You need to run this application as root") self.notify_status("not_root", \ {"not_root":"You dont't have permission"}) if not os.path.isdir(output_folder): try: os.mkdir(output_folder) except Exception as e: log.info("The folder is invalid. {0}".format(e)) self.notify_status("invalid_folder",\ {"invalid_folder":output_folder}) raise InvalidFolder("Invalid folder {0}".format(output_folder))
def notify_percent(self): #refresh the interface percentage percent = (self.processed_blocks/float(self.total_blocks)) * 100 if percent > self.current_percent: self.current_percent = percent self.notify_status("progress", {"percent": percent}) #verify stderr from partclone if self.partclone_stderr != None: partclone_status = self.partclone_stderr.readline() if partclone_status.startswith("Partclone successfully cloned the device"): self.partclone_sucess = True else: if self.data_is_eof: part_list = partclone_status.split() if part_list[0] == "current": if len(part_list) >= 13: try: status = partclone_status.split()[13].split(",")[0] status2 = status.split("%")[0] self.notify_status("waiting_partclone",{"partclone_percent":float(status2)}) except Exception as e: log.info(e) raise ErrorCreatingImage("Create image wasn't made with success")
self.notify_status("no_valid_partitions", \ {"no_valid_partitions":partitions}) raise ErrorRestoringImage("No valid partitions found") self.timer.stop() if self.expand != 2: if information.get_image_is_disk(): self.expand_last_partition(self.expand) if self.canceled: self.notify_status("canceled", {"operation": "Restore image"}) else: self._finish() log.info("Restoration finished") log.info("Iniciando gtk grubinstall") cmd = "{0}".format(which("grubinstall")) try: os.system("{0} &".format(cmd)) except: log.error("Erro ao iniciar grubinstall. {0}".format(e)) def expand_last_partition(self,opt_expand): # After all data is copied to the disk # we instance class again to reload sync() device = Device(self.target_device) disk = Disk(device) partition = disk.get_last_partition()
def restore_image(self): """ """ if is_mounted(self.target_device): raise DeviceIsMounted("Please umount first") self.active = True information = Information(self.image_path) information.load() if self.partitions: information.set_partitions(self.partitions) image_name = information.get_image_name() compressor_level = information.get_image_compressor_level() partitions = information.get_partitions() # Get total size total_bytes = 0 for part in partitions: total_bytes += part.size self.total_blocks = long(math.ceil(total_bytes / float(BLOCK_SIZE))) device = Device(self.target_device) if device.is_disk() != \ information.get_image_is_disk(): log.error("Invalid target device %s" % device.path) raise ErrorRestoringImage("Invalid target device") try: disk = Disk(device) except _ped.DiskLabelException: try: device.fix_disk_label() disk = Disk(device) except: log.error("Unrecognized disk label") raise ErrorRestoringImage("Unrecognized disk label") if information.get_image_is_disk(): log.info("Restoring MBR and Disk Layout") mbr = Mbr(self.image_path) mbr.restore_from_file(self.target_device) dlm = DiskLayoutManager(self.image_path) dlm.restore_from_file(disk, self.expand) self.timer.start() for part in partitions: if not self.active: break if information.get_image_is_disk(): partition = disk.get_partition_by_number( part.number, part.type) else: parent_path = get_parent_path(self.target_device) parent_device = Device(parent_path) parent_disk = Disk(parent_device) partition = parent_disk.get_partition_by_path( self.target_device, part.type) log.info("Restoring partition {0}".format(partition.get_path())) if partition is None: raise ErrorRestoringImage("No valid partitions found") if hasattr(part, "uuid"): partition.filesystem.open_to_write(part.uuid) else: partition.filesystem.open_to_write() if hasattr(part, "label"): partition.filesystem.write_label(part.label) if partition.filesystem.is_swap(): continue pattern = FILE_PATTERN.format(name=image_name, partition=part.number, volume="{volume}") volumes = 1 if hasattr(part, "volumes"): volumes = part.volumes image_reader = ImageReaderFactory(self.image_path, pattern, volumes, compressor_level, self.notify_status) extract_callback = None if compressor_level: compressor = Compressor(compressor_level) extract_callback = compressor.extract self.buffer_manager = BufferManagerFactory(image_reader.read_block, extract_callback) # open the file after instantiating BufferManager, cause of a # problem on multiprocessing module, FD_CLOEXE doesn't work # (I don't want to dup the file descriptor). image_reader.open() self.buffer_manager.start() buffer = self.buffer_manager.output_buffer while self.active: try: data = buffer.get() except IOError, e: if e.errno == errno.EINTR: self.cancel() break if data == EOF: break try: partition.filesystem.write_block(data) except ErrorWritingToDevice, e: if not self.canceled: self.stop() raise e self.processed_blocks += 1
def create_image(self): """ """ if is_mounted(self.device_path): log.error("The partition {0} is mounted, please umount first, and try again".format(self.device_path)) self.notify_status("mounted_partition_error",{"mounted_partition_error":self.device_path}) raise DeviceIsMounted("Please umount first") self.active = True device = Device(self.device_path) disk = Disk(device) if device.is_disk(): try: mbr = Mbr(self.target_path) mbr.save_to_file(self.device_path) dlm = DiskLayoutManager(self.target_path) dlm.save_to_file(disk) except Exception as e: log.info(e) self.notify_status("write_error", \ {"write_error":self.target_path}) raise ErrorWritingToDevice("Write error in {0}".format(self.target_path)) partition_list = disk.get_valid_partitions(self.raw) if not partition_list: raise ErrorCreatingImage("Partition(s) hasn't a " +\ "valid filesystem") # check partitions filesystem if not self.raw: for part in partition_list: log.info("Checking filesystem of {0}".format(part.get_path())) self.notify_status("checking_filesystem", {"device": part.get_path()}) if not part.filesystem.check(): log.error("{0} Filesystem is not clean".\ format(part.get_path())) raise ErrorCreatingImage("{0} Filesystem is not clean".\ format(part.get_path())) # fill partitions with zeroes if self.raw and self.fill_with_zeros: for part in partition_list: log.info("{0} Filling with zeros".format(part.get_path())) self.notify_status("filling_with_zeros", {"device": part.get_path()}) part.filesystem.fill_with_zeros() # get total size total_bytes = 0 for part in partition_list: total_bytes += part.filesystem.get_used_size() self.total_blocks = long(math.ceil(total_bytes/float(BLOCK_SIZE))) information = Information(self.target_path) information.set_image_is_disk(device.is_disk()) information.set_image_name(self.image_name) information.set_image_compressor_level(self.compressor_level) if device.is_disk(): disk_info = DiskInfo() disk_dict = disk_info.formated_disk(self.device_path) information.set_disk_size(disk_dict["size"]) # TODO: Abstract this whole part, when creating isos, # splitting in files, etc... self.timer.start() remaining_size = self.split_size if self.create_iso: remaining_size -= BASE_SYSTEM_SIZE slices = dict() # Used when creating iso iso_volume = 1 # Used when creating iso for part in partition_list: if not self.active: break log.info("Creating image of {0}".format(part.get_path())) self.notify_status("image_creator", \ {"image_creator ": part.get_path()}) number = part.get_number() uuid = part.filesystem.uuid() label = part.filesystem.read_label() type = part.filesystem.type part.filesystem.open_to_read() #check if partclone is running if type in ("ext2","ext3","ext4"): self.partclone_stderr = part.filesystem.get_error_ext() compact_callback = None if self.compressor_level: compressor = Compressor(self.compressor_level) compact_callback = compressor.compact self.buffer_manager = BufferManagerFactory( part.filesystem.read_block, self.notify_status, compact_callback) self.buffer_manager.start() buffer = self.buffer_manager.output_buffer volumes = 1 while self.active: total_written = 0 # Used to help splitting the file pattern = FILE_PATTERN.format(name=self.image_name, partition=number, volume=volumes) file_path = self.target_path + pattern try: fd = open(file_path, "wb") except Exception as e: log.info(e) self.notify_status("open_file", \ {"open_file":file_path}) raise ImageNotFound("The file wasn't found {0}". \ format(file_path)) next_partition = False while self.active: try: data = buffer.get() except IOError, e: #self.notify_status("read_buffer_error", \ # {"read_buffer_error":str(e)}) if e.errno == errno.EINTR: self.notify_status("read_buffer_error", \ {"read_buffer_error":str(e)}) data = "" self.cancel() raise ErrorReadingFromDevice(e) break if data == EOF: if (self.partclone_stderr != None): self.data_is_eof = True while self.partclone_sucess == False: pass self.partclone_stderr = None self.partclone_sucess = False self.data_is_eof = False next_partition = True if self.create_iso: remaining_size -= total_written if not slices.has_key(iso_volume): slices[iso_volume] = list() slices[iso_volume].append(file_path) break try: fd.write(data) except Exception as e: log.info("{0}".format(e)) self.notify_status("disk_full") self.cancel() raise ErrorWritingToDevice("Error in write file {0}".\ format(file_path)) self.processed_blocks += 1 if self.split_size: bytes_written = len(data) total_written += bytes_written if (total_written + bytes_written) >= remaining_size: volumes += 1 remaining_size = self.split_size if self.create_iso: if not slices.has_key(iso_volume): slices[iso_volume] = list() slices[iso_volume].append(file_path) iso_volume += 1 break try: fd.close() except Exception as e: log.info(e) self.notify_status("write_error",{"write_error":e}) raise ErrorCloseToWrite("Close Error {0}".format(e)) if next_partition: break self.buffer_manager.join() part.filesystem.close() information.add_partition(number, type, volumes, part.filesystem.get_used_size(), uuid, label)
self.processed_blocks += 1 self.buffer_manager.join() partition.filesystem.close() self.timer.stop() if self.expand: if information.get_image_is_disk(): self.expand_last_partition() if self.canceled: self.notify_status("canceled", {"operation": "Restore image"}) else: self._finish() log.info("Restoration finished") def expand_last_partition(self): # After all data is copied to the disk # we instance class again to reload sync() device = Device(self.target_device) disk = Disk(device) partition = disk.get_last_partition() if partition is not None: if partition.type == PARTITION_NORMAL: log.info("Expanding {0} filesystem".\ format(partition.get_path())) self.notify_status("expand", {"device": partition.get_path()}) partition.filesystem.resize()
def build_grub_legacy_menu(self,boot_folder, dev_boot_tuples=None): ''' search for linux kernels in all devices. search windows boot files. built the menu.lst in the target device, also copy grub-legacy files there. ''' cont = 0 menu_linux = [] menu_windows = [] FILE = "{0}/grub/menu.lst".format(boot_folder) try: f = open(FILE,"w") except: os.makedirs("{0}/grub/".format(boot_folder)) ret,err,out = run_simple_command_echo("touch {0}/grub/menu.lst".format(boot_folder)) f = open(FILE,"w") menu_linux.append("#AUTOMAGIC GENERATED\n") menu_linux.append("default saved\n") menu_linux.append("timeout 10\n") menu_linux.append("password --md5 $1$7QG0J0$l2j8MS763EKQ3u.sDdh8Z0\n") dev = os.listdir("/dev") for i in dev: if ("sd" in i) and (len(i)==3): devices_linux,devices_windows = list_devices(i) if devices_linux is not None: for lin in devices_linux: directory = mount_partition(lin) boot_directory = directory+"/boot" try: filenames = os.listdir("{0}".format(boot_directory)) except: filenames=None try: filenames2 = os.listdir("{0}".format(directory)) except: filenames2 = None var_temp = None vmlinuz = None if filenames is not None: filenames.sort() boot_me = "/boot" for aux in filenames: if "init" in aux: initrd = aux if len(aux) < 12: var_temp="" else: var_temp = aux[11:] # take just the kernel version elif ((var_temp is not None) and ("vmlinuz" in aux) and (var_temp in aux)) or ("vmlinuz"==aux): vmlinuz = aux cont+=1 if (filenames2 is not None) and (vmlinuz is None): filenames2.sort() boot_me = "" for aux in filenames2: if "init" in aux: initrd = aux if len(aux) < 12: var_temp="" else: var_temp = aux[11:] # take just the kernel version elif ((var_temp is not None) and ("vmlinuz" in aux) and (var_temp in aux)) or ("vmlinuz"==aux): vmlinuz = aux#+"MAOEEE" cont+=1 if (vmlinuz is not None): line = distro_name(directory) if line is None: line = cont menu_linux.append("\ntitle Linux {0} in {1}\n".format(line,lin)) menu_linux.append("root (hd0,{0})\n".format(int(lin[8:])-1)) temp = False if (dev_boot_tuples is not None): for i in dev_boot_tuples: if lin in i[0]: temp = True menu_linux.append("kernel {0}/{1} root={2} ro quiet splash\ \n".format(boot_me,vmlinuz,i[1])) dev_boot_tuples.pop(dev_boot_tuples.index(i)) if not dev_boot_tuples: dev_boot_tuples = None if not temp: #if temp_dev is None: menu_linux.append("kernel {0}/{1} root={2} ro quiet splash\ \n".format(boot_me,vmlinuz,lin)) #else: # menu_linux.append("kernel {0}/{1} root = {2} ro quiet splash\ # \n".format(boot_me,vmlinuz,temp_dev)) # temp_dev = None menu_linux.append("initrd {0}/{1}\n".format(boot_me,initrd)) menu_linux.append("quiet\n") menu_linux.append("savedefault\n") else: temp_dev = lin umount_partition(directory) cont = 0 for win in devices_windows: cont+= 1 filenames = None directory = mount_partition(win) try: filenames = os.listdir("{0}".format(directory)) except: log.info("Folder {0} didn't exist or it'a empty".format(directory)) if filenames is not None: bootWin = False for i in filenames: if "boot" in i.lower(): bootWin = True if bootWin: windev = int(win[8:]) menu_windows.append("\ntitle Windows {0}\n".format(cont)) ''' the two line below should exist if windows is on sdb ''' if "1" not in win: #if windows is not in the firs filesystem menu_windows.append("map (hd0) (hd{0})\n".format(windev)) menu_windows.append("map (hd{0}) (hd0)\n".format(windev)) menu_windows.append("rootnoverify (hd0,{0})\n".format(windev-1)) menu_windows.append("makeactive\n") menu_windows.append("chainloader +1\n") for i in menu_linux: f.write(i) for i in menu_windows: f.write(i) f.close()
def install_syslinux(self, device, directory): boot_folder = directory+"boot" dev = device[:8] try: log.info("cp /usr/lib/syslinux/menu.c32 {0}/syslinux".format(boot_folder)) copyFile("/usr/lib/syslinux/menu.c32", boot_folder+"/syslinux") log.info("cp /usr/lib/syslinux/chain.c32 {0}/syslinux".format(boot_folder)) copyFile("/usr/lib/syslinux/chain.c32", boot_folder+"/syslinux") log.info("cp /usr/lib/syslinux/reboot.c32 {0}/syslinux".format(boot_folder)) copyFile("/usr/lib/syslinux/reboot.c32", boot_folder+"/syslinux") log.info("cp /usr/lib/syslinux/poweroff.com {0}/syslinux".format(boot_folder)) copyFile("/usr/lib/syslinux/poweroff.com", boot_folder+"/syslinux") except: log.error("Error copying files") return False try: aux = get_filesystem_type(device) if "fat" in aux: run_simple_command_echo("syslinux -d {0}/syslinux {1}".format(boot_folder,device),True) elif "ext" in aux: log.info("extlinux --install {0}/syslinux".format(boot_folder)) run_simple_command_echo("extlinux --install {0}/syslinux".format(boot_folder),True) else: log.error("Filesystem not accepted.") return False except: log.error("installing syslinux in {0} failed".format(device)) return False try: run_simple_command_echo("dd if=/usr/lib/syslinux/mbr.bin of={0} \ bs=440 conv=notrunc count=1".format(dev),True) except: log.error("dd failed") return False if not get_boot_flag(device): unset_all_boot_flags(device) if set_boot_flag(device): log.info("{0} has been set as bootable device".format(device)) return True
def undo_chroot(real_root): log.info("Exiting chroot") os.fchdir(real_root) os.chroot(".") os.close(real_root) os.chdir("/")
class ImageCreator: def __init__(self, source_device, output_folder, status_callback, image_name="image", compressor_level=6, raw=False, split_size=0, create_iso=False, fill_with_zeros=False): assert check_if_root(), "You need to run this application as root" assert os.path.isdir(output_folder), "{0} folder is invalid".\ format(output_folder) self.image_name = image_name self.device_path = source_device self.target_path = adjust_path(output_folder) self.notify_status = status_callback self.compressor_level = compressor_level self.raw = raw self.split_size = split_size self.create_iso = create_iso self.fill_with_zeros = fill_with_zeros self.timer = Timer(self.notify_percent) self.total_blocks = 0 self.processed_blocks = 0 self.current_percent = -1 self.active = False self.canceled = False def notify_percent(self): percent = (self.processed_blocks/float(self.total_blocks)) * 100 if percent > self.current_percent: self.current_percent = percent self.notify_status("progress", {"percent": percent}) def create_image(self): """ """ if is_mounted(self.device_path): raise DeviceIsMounted("Please umount first") self.active = True device = Device(self.device_path) disk = Disk(device) if device.is_disk(): mbr = Mbr(self.target_path) mbr.save_to_file(self.device_path) dlm = DiskLayoutManager(self.target_path) dlm.save_to_file(disk) partition_list = disk.get_valid_partitions(self.raw) if not partition_list: raise ErrorCreatingImage("Partition(s) hasn't a " +\ "valid filesystem") # check partitions filesystem if not self.raw: for part in partition_list: log.info("Checking filesystem of {0}".format(part.get_path())) self.notify_status("checking_filesystem", {"device": part.get_path()}) if not part.filesystem.check(): log.error("{0} Filesystem is not clean".\ format(part.get_path())) raise ErrorCreatingImage("{0} Filesystem is not clean".\ format(part.get_path())) # fill partitions with zeroes if self.raw and self.fill_with_zeros: for part in partition_list: log.info("{0} Filling with zeros".format(part.get_path())) self.notify_status("filling_with_zeros", {"device": part.get_path()}) part.filesystem.fill_with_zeros() # get total size total_bytes = 0 for part in partition_list: total_bytes += part.filesystem.get_used_size() self.total_blocks = long(math.ceil(total_bytes/float(BLOCK_SIZE))) information = Information(self.target_path) information.set_image_is_disk(device.is_disk()) information.set_image_name(self.image_name) information.set_image_compressor_level(self.compressor_level) # TODO: Abstract this whole part, when creating isos, # splitting in files, etc... self.timer.start() remaining_size = self.split_size if self.create_iso: remaining_size -= BASE_SYSTEM_SIZE slices = dict() # Used when creating iso iso_volume = 1 # Used when creating iso for part in partition_list: if not self.active: break log.info("Creating image of {0}".format(part.get_path())) number = part.get_number() uuid = part.filesystem.uuid() label = part.filesystem.read_label() type = part.filesystem.type part.filesystem.open_to_read() compact_callback = None if self.compressor_level: compressor = Compressor(self.compressor_level) compact_callback = compressor.compact self.buffer_manager = BufferManagerFactory( part.filesystem.read_block, compact_callback) self.buffer_manager.start() buffer = self.buffer_manager.output_buffer volumes = 1 while self.active: total_written = 0 # Used to help splitting the file pattern = FILE_PATTERN.format(name=self.image_name, partition=number, volume=volumes) file_path = self.target_path + pattern fd = open(file_path, "wb") next_partition = False while self.active: try: data = buffer.get() except IOError, e: if e.errno == errno.EINTR: self.cancel() break if data == EOF: next_partition = True if self.create_iso: remaining_size -= total_written if not slices.has_key(iso_volume): slices[iso_volume] = list() slices[iso_volume].append(file_path) break fd.write(data) self.processed_blocks += 1 if self.split_size: bytes_written = len(data) total_written += bytes_written if (total_written + bytes_written) >= remaining_size: volumes += 1 remaining_size = self.split_size if self.create_iso: if not slices.has_key(iso_volume): slices[iso_volume] = list() slices[iso_volume].append(file_path) iso_volume += 1 break fd.close() if next_partition: break self.buffer_manager.join() part.filesystem.close() information.add_partition(number, type, volumes, part.filesystem.get_used_size(), uuid, label) # We dont need to save the data of the swap partition # we just copy the informations and re-create when # restoring swap = disk.get_swap_partition() if swap is not None: log.info("Swap path {0}".format(swap.get_path())) number = swap.get_number() uuid = swap.filesystem.uuid() type = swap.filesystem.type information.add_partition(number, type, 0, 0, uuid) information.save() self.stop() if self.create_iso: log.info("Starting create ISO operation") iso_creator = IsoCreator(self.target_path, slices, self.image_name, self.notify_status, device.is_disk()) iso_creator.run() if self.canceled: self.notify_status("canceled", {"operation": "Create image"}) else: self.notify_status("finish") log.info("Creation finished")
def cancel(self): if not self.canceled: log.info("Create image canceled") self.canceled = True self.stop()
def expand_last_partition(self,opt_expand): # After all data is copied to the disk # we instance class again to reload sync() device = Device(self.target_device) disk = Disk(device) partition = disk.get_last_partition() if partition is not None: if partition.type == PARTITION_NORMAL: expander = PartitionExpander(device.path) log.info("Checking and try expand {0}".format(partition.get_path())) new_size = expander.try_expand() log.info("The new_size of the disk will be {0}".format(new_size)) if new_size!= -1: if opt_expand == 0: log.info("Expanding {0} filesystem".format(partition.get_path())) self.notify_status("expand", {"device": partition.get_path()}) returncode = partition.filesystem.resize() if returncode == True: log.info("Resize in {0} was made with sucess".format(partition.get_path())) else: log.info("Resize in {0} failed - Versao sem mensagem!".format(partition.get_path())) #self.notify_status("expand_last_partition_error", {"last_partition":partition.get_path()}) #self.canceled = True else: if opt_expand == 1: log.info("Formating {0} filesystem".format(partition.get_path())) self.notify_status("format", {"device": partition.get_path()}) partition.filesystem.format_filesystem()
def create_image(self): """ """ if is_mounted(self.device_path): raise DeviceIsMounted("Please umount first") self.active = True device = Device(self.device_path) disk = Disk(device) if device.is_disk(): mbr = Mbr(self.target_path) mbr.save_to_file(self.device_path) dlm = DiskLayoutManager(self.target_path) dlm.save_to_file(disk) partition_list = disk.get_valid_partitions(self.raw) if not partition_list: raise ErrorCreatingImage("Partition(s) hasn't a " +\ "valid filesystem") # check partitions filesystem if not self.raw: for part in partition_list: log.info("Checking filesystem of {0}".format(part.get_path())) self.notify_status("checking_filesystem", {"device": part.get_path()}) if not part.filesystem.check(): log.error("{0} Filesystem is not clean".\ format(part.get_path())) raise ErrorCreatingImage("{0} Filesystem is not clean".\ format(part.get_path())) # fill partitions with zeroes if self.raw and self.fill_with_zeros: for part in partition_list: log.info("{0} Filling with zeros".format(part.get_path())) self.notify_status("filling_with_zeros", {"device": part.get_path()}) part.filesystem.fill_with_zeros() # get total size total_bytes = 0 for part in partition_list: total_bytes += part.filesystem.get_used_size() self.total_blocks = long(math.ceil(total_bytes/float(BLOCK_SIZE))) information = Information(self.target_path) information.set_image_is_disk(device.is_disk()) information.set_image_name(self.image_name) information.set_image_compressor_level(self.compressor_level) # TODO: Abstract this whole part, when creating isos, # splitting in files, etc... self.timer.start() remaining_size = self.split_size if self.create_iso: remaining_size -= BASE_SYSTEM_SIZE slices = dict() # Used when creating iso iso_volume = 1 # Used when creating iso for part in partition_list: if not self.active: break log.info("Creating image of {0}".format(part.get_path())) number = part.get_number() uuid = part.filesystem.uuid() label = part.filesystem.read_label() type = part.filesystem.type part.filesystem.open_to_read() compact_callback = None if self.compressor_level: compressor = Compressor(self.compressor_level) compact_callback = compressor.compact self.buffer_manager = BufferManagerFactory( part.filesystem.read_block, compact_callback) self.buffer_manager.start() buffer = self.buffer_manager.output_buffer volumes = 1 while self.active: total_written = 0 # Used to help splitting the file pattern = FILE_PATTERN.format(name=self.image_name, partition=number, volume=volumes) file_path = self.target_path + pattern fd = open(file_path, "wb") next_partition = False while self.active: try: data = buffer.get() except IOError, e: if e.errno == errno.EINTR: self.cancel() break if data == EOF: next_partition = True if self.create_iso: remaining_size -= total_written if not slices.has_key(iso_volume): slices[iso_volume] = list() slices[iso_volume].append(file_path) break fd.write(data) self.processed_blocks += 1 if self.split_size: bytes_written = len(data) total_written += bytes_written if (total_written + bytes_written) >= remaining_size: volumes += 1 remaining_size = self.split_size if self.create_iso: if not slices.has_key(iso_volume): slices[iso_volume] = list() slices[iso_volume].append(file_path) iso_volume += 1 break fd.close() if next_partition: break self.buffer_manager.join() part.filesystem.close() information.add_partition(number, type, volumes, part.filesystem.get_used_size(), uuid, label)
def restore_image(self): """ """ if is_mounted(self.target_device): raise DeviceIsMounted("Please umount first") self.active = True information = Information(self.image_path) information.load() if self.partitions: information.set_partitions(self.partitions) image_name = information.get_image_name() compressor_level = information.get_image_compressor_level() partitions = information.get_partitions() # Get total size total_bytes = 0 for part in partitions: total_bytes += part.size self.total_blocks = long(math.ceil(total_bytes/float(BLOCK_SIZE))) device = Device(self.target_device) if device.is_disk() != \ information.get_image_is_disk(): log.error("Invalid target device %s" % device.path) raise ErrorRestoringImage("Invalid target device") try: disk = Disk(device) except _ped.DiskLabelException: try: device.fix_disk_label() disk = Disk(device) except: log.error("Unrecognized disk label") raise ErrorRestoringImage("Unrecognized disk label") if information.get_image_is_disk(): log.info("Restoring MBR and Disk Layout") mbr = Mbr(self.image_path) mbr.restore_from_file(self.target_device) dlm = DiskLayoutManager(self.image_path) dlm.restore_from_file(disk, self.expand) self.timer.start() for part in partitions: if not self.active: break if information.get_image_is_disk(): partition = disk.get_partition_by_number(part.number, part.type) else: parent_path = get_parent_path(self.target_device) parent_device = Device(parent_path) parent_disk = Disk(parent_device) partition = parent_disk.get_partition_by_path( self.target_device, part.type) log.info("Restoring partition {0}".format(partition.get_path())) if partition is None: raise ErrorRestoringImage("No valid partitions found") if hasattr(part, "uuid"): partition.filesystem.open_to_write(part.uuid) else: partition.filesystem.open_to_write() if hasattr(part, "label"): partition.filesystem.write_label(part.label) if partition.filesystem.is_swap(): continue pattern = FILE_PATTERN.format(name=image_name, partition=part.number, volume="{volume}") volumes = 1 if hasattr(part, "volumes"): volumes = part.volumes image_reader = ImageReaderFactory(self.image_path, pattern, volumes, compressor_level, self.notify_status) extract_callback = None if compressor_level: compressor = Compressor(compressor_level) extract_callback = compressor.extract self.buffer_manager = BufferManagerFactory(image_reader.read_block, extract_callback) # open the file after instantiating BufferManager, cause of a # problem on multiprocessing module, FD_CLOEXE doesn't work # (I don't want to dup the file descriptor). image_reader.open() self.buffer_manager.start() buffer = self.buffer_manager.output_buffer while self.active: try: data = buffer.get() except IOError, e: if e.errno == errno.EINTR: self.cancel() break if data == EOF: break try: partition.filesystem.write_block(data) except ErrorWritingToDevice, e: if not self.canceled: self.stop() raise e self.processed_blocks += 1
def restore_image(self): """ """ invalid_partitions = False if is_mounted(self.target_device): log.error("The partition {0} is mounted, please umount first, and try again".format(self.target_device)) self.notify_status("mounted_partition_error",{"mounted_partition_error":self.target_device}) raise DeviceIsMounted("Please umount first") self.active = True information = Information(self.image_path) information.load() if self.partitions: information.set_partitions(self.partitions) image_name = information.get_image_name() compressor_level = information.get_image_compressor_level() partitions = information.get_partitions() # Get total size total_bytes = 0 for part in partitions: total_bytes += part.size self.total_blocks = long(math.ceil(total_bytes/float(BLOCK_SIZE))) device = Device(self.target_device) if device.is_disk() != \ information.get_image_is_disk(): log.error("Invalid target device %s" % device.path) self.notify_status("write_error", \ {"write_error":device_path}) raise ErrorRestoringImage("Invalid target device") try: disk = Disk(device) except _ped.DiskLabelException: try: device.fix_disk_label() disk = Disk(device) except: log.error("Unrecognized disk label") raise ErrorRestoringImage("Unrecognized disk label") if information.get_image_is_disk(): if ("msdos" not in disk.getPedDisk().type.name): #se a tabela nao for msdos, recria ela como msdos para nao haver problemas d = disk_new_fresh(device.getPedDevice(), _ped.disk_type_get("msdos")) d.commit_to_dev() disk = Disk(device) #Get total disk target size disk_size = get_disk_size(self.target_device) if (total_bytes > disk_size): log.info("Total size of image is {0}".format(total_bytes)) log.info("Total size of {0} is {1}".format(self.target_device,disk_size)) log.error("The size of {0} is {1}, is not enough to apply the selected image".format(self.target_device, disk_size)) disk_space_info = [] disk_space_info.append(total_bytes) disk_space_info.append(disk_size) self.notify_status("no_enough_space", {"disk_minimum_size":disk_space_info}) raise ErrorRestoringImage("No enough space on disk") log.info("Restoring MBR and Disk Layout") mbr = Mbr(self.image_path) try: mbr.restore_from_file(self.target_device) except Exception as e: log.error("Error to restore the Mbr file") image_path = self.image_path.split("/")[3] + "/mbr.bin" self.notify_status("file_not_found",{"file_not_found":image_path}) raise ErrorFileNotFound("File not Found {0}".format(image_path)) dlm = DiskLayoutManager(self.image_path) #try: if self.expand != 2: dlm.restore_from_file(disk, True) else: dlm.restore_from_file(disk, False) #except Exception as e: # log.error("Error to restore the disk.dl file") # image_path = self.image_path.split("/")[3] + "/disk.dl" # self.notify_status("file_not_found",{"file_not_found":image_path}) # raise ErrorFileNotFound("File not found {0}".format(image_path)) else: parent_path = get_parent_path(self.target_device) parent_device = Device(parent_path) parent_disk = Disk(parent_device) partition = parent_disk.get_partition_by_path( self.target_device, part.type) part_size = partition.getSize('b') if (total_bytes > part_size): part_space_info = [] part_space_info.append(total_bytes) part_space_info.append(part_size) log.error("The partition selected is smaller than the image") self.notify_status("no_enough_space_part", {"disk_minimum_size":part_space_info}) raise ErrorRestoringImage("No enought space on partition") self.timer.start() total_partitions = len(partitions) for part in partitions: total_partitions -= 1 if not self.active: break if (self.expand == 3) and (total_partitions == 0): break if information.get_image_is_disk(): partition = disk.get_partition_by_number(part.number, part.type) else: parent_path = get_parent_path(self.target_device) parent_device = Device(parent_path) parent_disk = Disk(parent_device) partition = parent_disk.get_partition_by_path( self.target_device, part.type) if partition is None: invalid_partitions = True continue log.info("Restoring partition {0}".format(partition.get_path())) self.notify_status("restore_partition",\ {"restoring_partition":partition.get_path()}) invalid_partitions = False if hasattr(part, "uuid"): partition.filesystem.open_to_write(part.uuid) else: partition.filesystem.open_to_write() if hasattr(part, "label"): partition.filesystem.write_label(part.label) if partition.filesystem.is_swap(): continue pattern = FILE_PATTERN.format(name=image_name, partition=part.number, volume="{volume}") volumes = 1 if hasattr(part, "volumes"): volumes = part.volumes try: image_reader = ImageReaderFactory(self.image_path, pattern, volumes, compressor_level, self.notify_status) except Exception as e: log.info(e) extract_callback = None if compressor_level: compressor = Compressor(compressor_level) extract_callback = compressor.extract self.buffer_manager = BufferManagerFactory(image_reader.read_block, self.notify_status, extract_callback) # open the file after instantiating BufferManager, cause of a # problem on multiprocessing module, FD_CLOEXE doesn't work # (I don't want to dup the file descriptor). image_reader.open() self.buffer_manager.start() buffer = self.buffer_manager.output_buffer while self.active: try: data = buffer.get() except IOError, e: if e.errno == errno.EINTR: self.notify_status("read_buffer_error",{"read_buffer_error":str(e)}) data = "" self.cancel() raise ErrorReadingFromDevice(e) break if data == EOF: break try: partition.filesystem.write_block(data) except ErrorWritingToDevice, e: self.notify_status("write_partition_error") if not self.canceled: self.stop() raise e self.processed_blocks += 1
self.buffer_manager.join() partition.filesystem.close() self.timer.stop() if self.expand: if information.get_image_is_disk(): self.expand_last_partition() if self.canceled: self.notify_status("canceled", {"operation": "Restore image"}) else: self._finish() log.info("Restoration finished") def expand_last_partition(self): # After all data is copied to the disk # we instance class again to reload sync() device = Device(self.target_device) disk = Disk(device) partition = disk.get_last_partition() if partition is not None: if partition.type == PARTITION_NORMAL: log.info("Expanding {0} filesystem".\ format(partition.get_path())) self.notify_status("expand", {"device": partition.get_path()}) partition.filesystem.resize()