[gparted] Added support to lost data recovery using gpart



commit ef37bdb7de1bbdc145aa40ae6e66a88e0e3e5ae9
Author: Joan Lledó <joanlluislledo gmail com>
Date:   Fri Jan 28 19:09:21 2011 +0100

    Added support to lost data recovery using gpart

 include/Dialog_Rescue_Data.h |   77 +++++++
 include/GParted_Core.h       |    2 +
 include/Makefile.am          |    1 +
 include/Utils.h              |    1 +
 include/Win_GParted.h        |    3 +
 po/POTFILES.in               |    1 +
 src/Dialog_Rescue_Data.cc    |  485 ++++++++++++++++++++++++++++++++++++++++++
 src/GParted_Core.cc          |   36 +++
 src/Makefile.am              |    1 +
 src/Utils.cc                 |   10 +
 src/Win_GParted.cc           |   87 ++++++++-
 11 files changed, 702 insertions(+), 2 deletions(-)
---
diff --git a/include/Dialog_Rescue_Data.h b/include/Dialog_Rescue_Data.h
new file mode 100644
index 0000000..b7ca417
--- /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 <gtkmm/dialog.h>
+#include <gtkmm/frame.h>
+#include <vector>
+
+namespace GParted
+{
+
+class Dialog_Rescue_Data : public Gtk::Dialog
+{
+public:
+	Dialog_Rescue_Data();
+
+	void init_partitions(Device *parentDevice, const Glib::ustring &buff);
+
+	std::vector<Partition> 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<Partition> partitions; //Partitions readed from the buffer
+	std::vector<int> 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::vector<int>inconsistencies_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 e1656d8..55bd6f5 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<Glib::ustring> & user_devices ) ;
 	void set_devices( std::vector<Device> & 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<Glib::ustring> device_paths ;
 	bool probe_devices ;
 	Glib::ustring thread_status_message;  //Used to pass data to show_pulsebar method
+	Glib::RefPtr<Glib::IOChannel> iocInput, iocOutput; // Used to send data to gpart command
 	
 	std::map< Glib::ustring, std::vector<Glib::ustring> > mount_info ;
 	std::map< Glib::ustring, std::vector<Glib::ustring> > fstab_info ;
diff --git a/include/Makefile.am b/include/Makefile.am
index 030e59f..a0ab11d 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 4f8bb29..180416b 100644
--- a/include/Utils.h
+++ b/include/Utils.h
@@ -156,6 +156,7 @@ public:
 	static void tokenize( const Glib::ustring& str,
 	                      std::vector<Glib::ustring>& 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 871a49f..0235de7 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<Gtk::Label *> device_info ;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f0a6aa4..dc53a29 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 0000000..3abae0e
--- /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 <gtkmm/messagedialog.h>
+#include <gtkmm/stock.h>
+#include <gtkmm/checkbutton.h>
+#include <sstream>
+
+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<Partition> 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("<big><b>");
+	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("</b></big>");
+
+	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;i<this->partitions.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("<b>"+mountPoint+"</b>");
+
+		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;i<this->overlappedPartitions.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;i<this->overlappedPartitions.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;j<this->device->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_sector<this->device->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_sector<this->device->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_end<end_sector)
+		{
+			this->overlappedPartitions.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;i<this->inconsistencies_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 8b55a42..3ecf7cd 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -350,6 +350,42 @@ void GParted_Core::set_devices( std::vector<Device> & 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<std::string> 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<void>(),
+		&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 c76ec37..2def664 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 46be034..5e32783 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 fed0347..cd8ecaa 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 ) ) ;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]