diff --git a/include/Dialog_Rescue_Data.h b/include/Dialog_Rescue_Data.h new file mode 100644 index 00000000..b7ca417b --- /dev/null +++ b/include/Dialog_Rescue_Data.h @@ -0,0 +1,77 @@ +/* Copyright (C) 2010 Joan Lledó + * + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + * The dialog for mount old data + * Reads the output of gpart and build the dialog + * */ + +#ifndef DIALOG_RESCUE_DATA +#define DIALOG_RESCUE_DATA + +#include "../include/Device.h" +#include "../include/Partition.h" + +#include +#include +#include + +namespace GParted +{ + +class Dialog_Rescue_Data : public Gtk::Dialog +{ +public: + Dialog_Rescue_Data(); + + void init_partitions(Device *parentDevice, const Glib::ustring &buff); + + std::vector get_partitions(); + +private: + void draw_dialog(); + void create_list_of_fs(); + bool is_overlaping(int nPart); + void read_partitions_from_buffer(); + void check_overlaps(int nPart); + void open_ro_view(Glib::ustring mountPoint); + bool is_inconsistent(const Partition &part); + + Device *device; //Parent device + std::vector partitions; //Partitions readed from the buffer + std::vector overlappedPartitions;//List of guessed partitions that + //overlap active partitions + Glib::ustring device_path; + Sector device_length; + bool inconsistencies; //If some of the guessed partitions is inconsistent + int sector_size; + std::vectorinconsistencies_list; //List of inconsistent partitions + + // Output of gpart command + std::istringstream *buffer; + + //GUI stuff + Gtk::Frame *frm; + + //Callback + void on_view_clicked(int nPart); +}; + +} //GParted + + +#endif //DIALOG_RESCUE_DATA diff --git a/include/GParted_Core.h b/include/GParted_Core.h index e1656d82..55bd6f56 100644 --- a/include/GParted_Core.h +++ b/include/GParted_Core.h @@ -38,6 +38,7 @@ public: void find_supported_filesystems() ; void set_user_devices( const std::vector & user_devices ) ; void set_devices( std::vector & devices ) ; + void guess_partition_table(const Device & device, Glib::ustring &buff); bool snap_to_cylinder( const Device & device, Partition & partition, Glib::ustring & error ) ; bool snap_to_mebibyte( const Device & device, Partition & partition, Glib::ustring & error ) ; @@ -198,6 +199,7 @@ private: std::vector device_paths ; bool probe_devices ; Glib::ustring thread_status_message; //Used to pass data to show_pulsebar method + Glib::RefPtr iocInput, iocOutput; // Used to send data to gpart command std::map< Glib::ustring, std::vector > mount_info ; std::map< Glib::ustring, std::vector > fstab_info ; diff --git a/include/Makefile.am b/include/Makefile.am index 030e59f9..a0ab11d7 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -4,6 +4,7 @@ EXTRA_DIST = \ Device.h \ Dialog_Base_Partition.h \ Dialog_Disklabel.h \ + Dialog_Rescue_Data.h \ Dialog_Partition_Copy.h \ Dialog_Partition_Info.h \ Dialog_Partition_Label.h \ diff --git a/include/Utils.h b/include/Utils.h index 4f8bb295..180416b8 100644 --- a/include/Utils.h +++ b/include/Utils.h @@ -156,6 +156,7 @@ public: static void tokenize( const Glib::ustring& str, std::vector& tokens, const Glib::ustring& delimiters ) ; + static int convert_to_int(const Glib::ustring & src); }; diff --git a/include/Win_GParted.h b/include/Win_GParted.h index 871a49fc..0235de70 100644 --- a/include/Win_GParted.h +++ b/include/Win_GParted.h @@ -126,6 +126,7 @@ private: void thread_unmount_partition( bool * succes, Glib::ustring * error ) ; void thread_mount_partition( Glib::ustring mountpoint, bool * succes, Glib::ustring * error ) ; void thread_toggle_swap( bool * succes, Glib::ustring * error ) ; + void thread_guess_partition_table(); //signal handlers void open_operationslist() ; @@ -162,6 +163,7 @@ private: void toggle_swap_mount_state() ; void activate_mount_partition( unsigned int index ) ; void activate_disklabel() ; + void activate_attempt_rescue_data(); void activate_manage_flags() ; void activate_check() ; void activate_label_partition() ; @@ -243,6 +245,7 @@ private: unsigned short new_count;//new_count keeps track of the new created partitions FS fs ; bool OPERATIONSLIST_OPEN ; + Glib::ustring gpart_output;//Output of gpart command GParted_Core gparted_core ; std::vector device_info ; diff --git a/po/POTFILES.in b/po/POTFILES.in index f0a6aa46..dc53a29e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -11,6 +11,7 @@ src/Dialog_Partition_Resize_Move.cc src/Dialog_Progress.cc src/DialogFeatures.cc src/DialogManageFlags.cc +src/Dialog_Rescue_Data.cc src/DMRaid.cc src/GParted_Core.cc src/HBoxOperations.cc diff --git a/src/Dialog_Rescue_Data.cc b/src/Dialog_Rescue_Data.cc new file mode 100644 index 00000000..3abae0e3 --- /dev/null +++ b/src/Dialog_Rescue_Data.cc @@ -0,0 +1,485 @@ +/* Copyright (C) 2010 Joan Lledó + * + * 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "../include/Utils.h" +#include "../include/Dialog_Rescue_Data.h" + +#include +#include +#include +#include + +namespace GParted +{ + +#define tmp_prefix P_tmpdir "/gparted-roview-XXXXXX" + +//The constructor creates a empty dialog +Dialog_Rescue_Data::Dialog_Rescue_Data() +{ + this ->set_title( _("Search disk for file systems") ); + + this ->add_button( Gtk::Stock::CLOSE, Gtk::RESPONSE_CLOSE ); +} + +//getters +std::vector Dialog_Rescue_Data::get_partitions() +{ + return this->partitions; +} + +// Draws the dialog +void Dialog_Rescue_Data::draw_dialog() +{ + Glib::ustring *message; + + /*TO TRANSLATORS: looks like File systems found on on /dev/sdb */ + this ->set_title( String::ucompose( _("File systems found on on %1"), this->device_path ) ); + + message=new Glib::ustring(""); + if(!this->inconsistencies) + { + message->append(_("Data found")); + } + else + { + message->append(_("Data found with inconsistencies")); + + Glib::ustring msg_label=_("WARNING!: The file systems marked with (!) are inconsistent."); + msg_label.append("\n"); + msg_label.append(_("You might encounter errors trying to view these file systems.")); + + Gtk::Label *inconsis_label=manage(Utils::mk_label(msg_label)); + Gdk::Color c( "red" ); + inconsis_label->modify_fg(Gtk::STATE_NORMAL, c ); + this->get_vbox()->pack_end(*inconsis_label, Gtk::PACK_SHRINK, 5); + } + message->append(""); + + this->get_vbox()->set_spacing(5); + + Gtk::Label *msgLbl=Utils::mk_label(*message); + this->get_vbox()->pack_start(*msgLbl, Gtk::PACK_SHRINK); + + this->create_list_of_fs(); + + Glib::ustring info_txt=_("The 'View' buttons create read-only views of each file system."); + info_txt+="\n"; + info_txt+=_("All mounted views will be unmounted when you close this dialog."); + + Gtk::HBox *infoBox=manage(new Gtk::HBox()); + Gtk::Image *infoImg=manage(new Gtk::Image( Gtk::Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG)); + Gtk::Label *infoLabel= manage(new Gtk::Label (info_txt)); + + infoBox->pack_start(*infoImg, Gtk::PACK_SHRINK, 5); + infoBox->pack_start(*infoLabel, Gtk::PACK_SHRINK); + + this->get_vbox()->pack_start(*infoBox, Gtk::PACK_SHRINK); + + this->show_all_children(); + + delete message; +} + +/* + * Create the list of the filesystems found */ +void Dialog_Rescue_Data::create_list_of_fs() +{ + Gtk::VBox *vb=manage(new Gtk::VBox()); + vb->set_border_width(5); + vb->set_spacing(5); + this->frm=Gtk::manage(new Gtk::Frame(_("File systems"))); + this->frm->add(*vb); + + for(unsigned int i=0;ipartitions.size();i++) + { + if(this->partitions[i].filesystem==GParted::FS_UNALLOCATED + || this->partitions[i].filesystem==GParted::FS_UNKNOWN + || this->partitions[i].filesystem==GParted::FS_UNFORMATTED + || this->partitions[i].filesystem==GParted::FS_EXTENDED + || this->partitions[i].type==GParted::TYPE_EXTENDED + || this->partitions[i].type==GParted::TYPE_UNALLOCATED) + { + continue; + } + + std::string fs_name=Utils::get_filesystem_string( this->partitions[i].filesystem ); + if(this->partitions[i].filesystem==FS_EXT2) + { + fs_name+="/3/4, ReiserFs or XFS"; + } + + /*TO TRANSLATORS: looks like 1: ntfs (10240 MiB)*/ + Gtk::Label *fsLbl= manage(new Gtk::Label( String::ucompose(_("#%1: %2 (%3 MiB)"), i+1, fs_name, (this->partitions[i].get_byte_length()/1024/1024)))); + if(this->is_inconsistent(this->partitions[i])) + { + fsLbl->set_label(fsLbl->get_label().append(" (!)")); + } + + Gtk::HBox *hb=manage(new Gtk::HBox()); + + Gtk::Button *btn=manage(new Gtk::Button(_("View"))); + + btn->signal_clicked().connect(sigc::bind(sigc::mem_fun(this, &Dialog_Rescue_Data::on_view_clicked), i)); + + hb->pack_start(*fsLbl, Gtk::PACK_SHRINK); + hb->pack_end(*btn, Gtk::PACK_SHRINK); + + vb->pack_start(*hb, Gtk::PACK_SHRINK); + } + + this->get_vbox()->pack_start(*this->frm, Gtk::PACK_SHRINK); +} + +/* + * Callback function for "View" button */ +void Dialog_Rescue_Data::on_view_clicked(int nPart) +{ + Partition part=this->partitions[nPart]; + + int initOffset=this->sector_size*part.sector_start; + int numSectors=part.sector_end-part.sector_start+1; + int totalSize=this->sector_size*numSectors; + + this->check_overlaps(nPart); + + char tmpDir[32]=tmp_prefix; + + mkdtemp(tmpDir); + + Glib::ustring mountPoint=tmpDir; + + Glib::ustring commandLine= String::ucompose("mount -o ro,loop,offset=%1,sizelimit=%2 %3 %4", initOffset, totalSize, this->device_path, mountPoint); + + int mountResult=Utils::execute_command(commandLine); + + if(mountResult!=0) + { + Glib::ustring error_txt=_("An error occurred while creating the read-only view."); + error_txt+="\n"; + error_txt+=_("Either the file system can not be mounted (like swap), or there are inconsistencies or errors in the file system."); + + //Dialog information + Gtk::MessageDialog errorDialog(*this, "", true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + errorDialog.set_message(_("Failed creating read-only view")); + errorDialog.set_secondary_text(error_txt); + + errorDialog.run(); + + return; + } + + this->open_ro_view(mountPoint); +} + +/* Opens the default browser in a directory */ +void Dialog_Rescue_Data::open_ro_view(Glib::ustring mountPoint) +{ + GError *error = NULL ; + GdkScreen *gscreen = NULL ; + + Glib::ustring uri = "file:" + mountPoint ; + + gscreen = gdk_screen_get_default() ; + +#ifdef HAVE_GTK_SHOW_URI + gtk_show_uri( gscreen, uri .c_str(), gtk_get_current_event_time(), &error ) ; +#else + Glib::ustring command = "gnome-open " + uri ; + gdk_spawn_command_line_on_screen( gscreen, command .c_str(), &error ) ; +#endif + + if ( error != NULL ) + { + Glib::ustring sec_text(_("Error:")); + sec_text.append("\n"); + sec_text.append(error ->message); + sec_text.append("\n"); + sec_text.append("\n"); + /*TO TRANSLATORS: looks like + * The file system is mounted on: + * /tmp/gparted-roview-Nlhb3R. */ + sec_text.append(_("The file system is mounted on:")); + sec_text.append("\n"); + sec_text.append(""+mountPoint+""); + + Gtk::MessageDialog dialog( *this + , _( "Unable to open the default file manager" ) + , false + , Gtk::MESSAGE_ERROR + , Gtk::BUTTONS_OK + , true + ) ; + dialog .set_secondary_text( sec_text, true ) ; + dialog .run() ; + } +} + +/* + * Checks if a guessed filesystem is overlapping other one and + * shows the dialog to umount it */ +void Dialog_Rescue_Data::check_overlaps(int nPart) +{ + if(is_overlaping(nPart)) + { + Gtk::MessageDialog overlapDialog(*this, "", true, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO, true); + overlapDialog.set_message(_("Warning: The detected file system area overlaps with at least one existing partition.")); + + Glib::ustring sec_text=_("It is recommended that you do not use any overlapping file systems to avoid disturbing existing data."); + sec_text+="\n"; + sec_text+=_("Do you want to try to deactivate the following mount points?"); + + for(unsigned int i=0;ioverlappedPartitions.size(); i++) + { + Glib::ustring ovrDevPath=this->device->partitions[i].get_path(); + Glib::ustring ovrDevMountPoint=this->device->partitions[i].get_mountpoint(); + + sec_text+="\n"+ovrDevPath+" mounted on "+ovrDevMountPoint; + } + + overlapDialog.set_secondary_text(sec_text); + + if(overlapDialog.run()==Gtk::RESPONSE_YES) + { + for(unsigned int i=0;ioverlappedPartitions.size(); i++) + { + Glib::ustring mountP=this->device->partitions[i].get_mountpoint(); + + Glib::ustring commandUmount= "umount "+mountP; + Utils::execute_command(commandUmount); + } + } + } +} + +/* + * Reads the output of gpart and sets some private variables */ +void Dialog_Rescue_Data::init_partitions(Device *parentDevice, const Glib::ustring & buff) +{ + this->device=parentDevice; + this->device_path=parentDevice->get_path(); + this->device_length=parentDevice->length; + this->sector_size=parentDevice->sector_size; + this->buffer=new std::istringstream(buff); + this->inconsistencies=false; + + std::string line; + + while(getline(*this->buffer, line)) + { + //If gpart finds inconsistencies, might not be able to mount some partitions + if(line.find("Number of inconsistencies found")!=Glib::ustring::npos) + { + this->inconsistencies=true; + } + + //Read the primary partition table + // (gpart only finds primary partitions) + if(line.find("Guessed primary partition table:")!=Glib::ustring::npos) + { + this->read_partitions_from_buffer(); + } + } + + this->draw_dialog(); +} + +/* Reads the output of gpart and builds the vector of guessed partitions */ +void Dialog_Rescue_Data::read_partitions_from_buffer() +{ + this->partitions.clear(); + + std::string line; + + while(getline(*this->buffer, line)) + { + if(line.find("Primary partition")!=line.npos) + { + // Parameters of Partition::Set + Partition part; + Glib::ustring dev_path=this->device_path; + Glib::ustring part_path; + int part_num; + PartitionType type=GParted::TYPE_PRIMARY; + FILESYSTEM fs=GParted::FS_UNALLOCATED; + Sector sec_start=0; + Sector sec_end=0; + Byte_Value sec_size=this->sector_size; + + // Get the part_num + Glib::ustring num=Utils::regexp_label(line, "^Primary partition\\(+([0-9])+\\)$"); + part_num=Utils::convert_to_int(num); + + //Get the part_path + part_path=String::ucompose ( "%1%2", this->device_path, num ); + + while(getline(*this->buffer, line)) + { + if(line=="") + { + break; + } + + if(line.find("type:")!=Glib::ustring::npos) + { + //Get the filesystem (needed for set the color of the visual partition) + int code=Utils::convert_to_int(Utils::regexp_label(line, "^[\t ]+type: +([0-9]+)+\\(+[a-zA-Z0-9]+\\)\\(+.+\\)$")); + + switch (code) + { + case 0x83: //FS code for ext2, reiserfs and xfs + { + fs=GParted::FS_EXT2; + break; + } + case 0x18: + case 0x82: + case 0xB8: //SWAP partition + { + fs=GParted::FS_LINUX_SWAP; + break; + } + case 0x04: + case 0x14: + case 0x86: + case 0xE4: //FAT16 + { + fs=GParted::FS_FAT16; + break; + } + case 0x0B: + case 0x0C: //FAT32 + { + fs=GParted::FS_FAT32; + break; + } + case 0x07: //NTFS and HPFS + { + fs=GParted::FS_NTFS; + break; + } + case 0x05: + case 0x0F: + case 0x85: //Extended + { + fs=GParted::FS_EXTENDED; + type=GParted::TYPE_EXTENDED; + break; + } + default: + { + fs=GParted::FS_UNKNOWN; + } + } + } + + if(line.find("size:")!=Glib::ustring::npos) + { + // Get the start sector + sec_start=Utils::convert_to_int(Utils::regexp_label(line, "^[\t ]+size: [0-9]+mb #s\\(+[0-9]+\\) s\\(+([0-9]+)+\\-+[0-9]+\\)$")); + + // Get the end sector + sec_end=Utils::convert_to_int(Utils::regexp_label(line, "^[\t ]+size: [0-9]+mb #s\\(+[0-9]+\\) s\\(+[0-9]+\\-+([0-9]+)+\\)$")); + } + } + + //No part found + if(sec_start==0 && sec_end==0) + { + continue; + } + + //Swap partitions don't contain data + if(fs==GParted::FS_LINUX_SWAP) + { + continue; + } + + part.Set(dev_path, part_path, part_num, + type, fs, sec_start, sec_end, sec_size, false, false); + + this->partitions.push_back(part); + } + } +} + + +/* + * Checks if the guessed partition is overlaping some active partition + */ +bool Dialog_Rescue_Data::is_overlaping(int nPart) +{ + bool result=false; + + Sector start_sector=this->partitions[nPart].sector_start; + Sector end_sector=this->partitions[nPart].sector_end; + + for(unsigned int j=0;jdevice->partitions.size();j++) + { + //only check if the partition if mounted + if(this->device->partitions[j].get_mountpoint()=="") + { + continue; + } + + //If the start sector is inside other partition + if(start_sector>this->device->partitions[j].sector_start && + start_sectordevice->partitions[j].sector_end) + { + this->overlappedPartitions.push_back(j); + result=true; + continue; + } + + //If the end sector is inside other partition + if(end_sector>this->device->partitions[j].sector_start && + end_sectordevice->partitions[j].sector_end) + { + this->overlappedPartitions.push_back(j); + result=true; + continue; + } + + //There is a partition between the sectors start and end + //If the end sector is inside other partition + if(this->device->partitions[j].sector_start>start_sector && + this->device->partitions[j].sector_endoverlappedPartitions.push_back(j); + result=true; + continue; + } + } + + return result; +} + +/* Check if a partition is inconsistent */ +bool Dialog_Rescue_Data::is_inconsistent(const Partition &part) +{ + for(unsigned int i=0;iinconsistencies_list.size();i++) + { + if (part.partition_number==this->inconsistencies_list[i]) + { + return true; + } + } + + return false; +} + +}//GParted diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc index 8b55a42e..3ecf7cd6 100644 --- a/src/GParted_Core.cc +++ b/src/GParted_Core.cc @@ -350,6 +350,42 @@ void GParted_Core::set_devices( std::vector & devices ) fstab_info .clear() ; } +// runs gpart on the specified parameter +void GParted_Core::guess_partition_table(const Device & device, Glib::ustring &buff) +{ + int pid, stdoutput, stderror; + std::vector argvproc, envpproc; + gunichar tmp; + + //Get the char string of the sector_size + std::ostringstream ssIn; + ssIn << device.sector_size; + Glib::ustring str_ssize = ssIn.str(); + + //Build the command line + argvproc.push_back("gpart"); + argvproc.push_back(device.get_path()); + argvproc.push_back("-s"); + argvproc.push_back(str_ssize); + + envpproc .push_back( "LC_ALL=C" ) ; + envpproc .push_back( "PATH=" + Glib::getenv( "PATH" ) ) ; + + Glib::spawn_async_with_pipes(Glib::get_current_dir(), argvproc, + envpproc, Glib::SPAWN_SEARCH_PATH, sigc::slot(), + &pid, NULL, &stdoutput, &stderror); + + this->iocOutput=Glib::IOChannel::create_from_fd(stdoutput); + + while(this->iocOutput->read(tmp)==Glib::IO_STATUS_NORMAL) + { + buff+=tmp; + } + this->iocOutput->close(); + + return; +} + void GParted_Core::set_thread_status_message( Glib::ustring msg ) { //Remember to clear status message when finished with thread. diff --git a/src/Makefile.am b/src/Makefile.am index c76ec37f..2def6642 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,6 +13,7 @@ gpartedbin_SOURCES = \ Device.cc \ Dialog_Base_Partition.cc \ Dialog_Disklabel.cc \ + Dialog_Rescue_Data.cc \ Dialog_Partition_Copy.cc \ Dialog_Partition_Info.cc \ Dialog_Partition_Label.cc \ diff --git a/src/Utils.cc b/src/Utils.cc index 46be0344..5e327834 100644 --- a/src/Utils.cc +++ b/src/Utils.cc @@ -481,5 +481,15 @@ void Utils::tokenize( const Glib::ustring& str, } } +// Converts a Glib::ustring into a int +int Utils::convert_to_int(const Glib::ustring & src) +{ + int ret_val; + std::istringstream stream(src); + stream >> ret_val; + + return ret_val; +} + } //GParted.. diff --git a/src/Win_GParted.cc b/src/Win_GParted.cc index fed03477..cd8ecaa2 100644 --- a/src/Win_GParted.cc +++ b/src/Win_GParted.cc @@ -20,6 +20,7 @@ #include "../include/Dialog_Progress.h" #include "../include/DialogFeatures.h" #include "../include/Dialog_Disklabel.h" +#include "../include/Dialog_Rescue_Data.h" #include "../include/Dialog_Partition_Resize_Move.h" #include "../include/Dialog_Partition_Copy.h" #include "../include/Dialog_Partition_New.h" @@ -183,6 +184,10 @@ void Win_GParted::init_menubar() menu = manage( new Gtk::Menu() ) ; menu ->items() .push_back( Gtk::Menu_Helpers::MenuElem( Glib::ustring( _("_Create Partition Table") ) + "...", sigc::mem_fun(*this, &Win_GParted::activate_disklabel) ) ); + + menu ->items() .push_back( Gtk::Menu_Helpers::MenuElem( Glib::ustring( _("_Attempt Data Rescue") ) + "...", + sigc::mem_fun(*this, &Win_GParted::activate_attempt_rescue_data) ) ); + menubar_main .items() .push_back( Gtk::Menu_Helpers::MenuElem( _("_Device"), *menu ) ); //partition @@ -1840,7 +1845,15 @@ void Win_GParted::thread_toggle_swap( bool * succes, Glib::ustring * error ) pulse = false ; } -void Win_GParted::toggle_swap_mount_state() +// Runs gpart in a thread +void Win_GParted::thread_guess_partition_table() +{ + this->gpart_output=""; + this->gparted_core.guess_partition_table(devices[ current_device ], this->gpart_output); + pulse=false; +} + +void Win_GParted::toggle_swap_mount_state() { int operation_count = partition_in_operation_queue_count( selected_partition ) ; if ( operation_count > 0 ) @@ -2078,7 +2091,77 @@ void Win_GParted::activate_disklabel() menu_gparted_refresh_devices() ; } } - + +//Runs when the Device->Attempt Rescue Data is clicked +void Win_GParted::activate_attempt_rescue_data() +{ + if(Glib::find_program_in_path( "gpart" ) .empty()) //Gpart must be installed to continue + { + Gtk::MessageDialog errorDialog(*this, "", true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + errorDialog.set_message(_("Command gpart was not found")); + errorDialog.set_secondary_text(_("This feature uses gpart. Please install gpart and try again.")); + + errorDialog.run(); + + return; + } + + //Dialog information + Glib::ustring sec_text = _( "A full disk scan is needed to find file systems." ) ; + sec_text += "\n" ; + sec_text +=_("The scan might take a very long time."); + sec_text += "\n" ; + sec_text += _("After the scan you can mount any discovered file systems and copy the data to other media.") ; + sec_text += "\n" ; + sec_text += _("Do you want to continue?"); + + Gtk::MessageDialog messageDialog(*this, "", true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK_CANCEL, true); + /*TO TRANSLATORS: looks like Search for file systems on /deb/sdb */ + messageDialog.set_message(String::ucompose(_("Search for file systems on %1"), devices[ current_device ] .get_path())); + messageDialog.set_secondary_text(sec_text); + + if(messageDialog.run()!=Gtk::RESPONSE_OK) + { + return; + } + + messageDialog.hide(); + + pulse=true; + this->thread = Glib::Thread::create( sigc::mem_fun( *this, &Win_GParted::thread_guess_partition_table ), true ) ; + + /*TO TRANSLATORS: looks like Searching for file systems on /deb/sdb */ + show_pulsebar(String::ucompose( _("Searching for file systems on %1"), devices[ current_device ] .get_path())); + + Dialog_Rescue_Data dialog; + dialog .set_transient_for( *this ); + + //Reads the output of gpart + dialog.init_partitions(&devices[ current_device ], this->gpart_output); + + if(dialog.get_partitions().size()==0) //No partitions found + { + //Dialog information + Gtk::MessageDialog errorDialog(*this, "", true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); + + /*TO TRANSLATORS: looks like No file systems found on /deb/sdb */ + errorDialog.set_message(String::ucompose(_("No file systems found on %1"), devices[ current_device ] .get_path())); + errorDialog.set_secondary_text(_("The disk scan by gpart did not find any recognizable file systems on this disk.")); + + errorDialog.run(); + return; + } + + dialog.run(); + dialog.hide(); + + Glib::ustring commandUmount= "umount /tmp/gparted-roview*"; + + Utils::execute_command(commandUmount); + + menu_gparted_refresh_devices() ; +} + void Win_GParted::activate_manage_flags() { get_window() ->set_cursor( Gdk::Cursor( Gdk::WATCH ) ) ;