gparted/src/Win_GParted.cc

3044 lines
111 KiB
C++
Raw Normal View History

/* Copyright (C) 2004 Bart
2015-02-01 13:14:05 -07:00
* Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Curtis Gedak
2004-09-19 14:24:53 -06:00
*
* 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 General Public License for more details.
2004-09-19 14:24:53 -06:00
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
2004-09-19 14:24:53 -06:00
*/
2004-09-19 14:24:53 -06:00
#include "../include/Win_GParted.h"
#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"
#include "../include/Dialog_Partition_Info.h"
#include "../include/Dialog_FileSystem_Label.h"
#include "../include/Dialog_Partition_Name.h"
#include "../include/DialogManageFlags.h"
#include "../include/Mount_Info.h"
#include "../include/OperationCopy.h"
#include "../include/OperationCheck.h"
#include "../include/OperationCreate.h"
#include "../include/OperationDelete.h"
#include "../include/OperationFormat.h"
#include "../include/OperationResizeMove.h"
#include "../include/OperationChangeUUID.h"
#include "../include/OperationLabelFileSystem.h"
#include "../include/OperationNamePartition.h"
#include "../include/Partition.h"
#include "../include/PartitionVector.h"
#include "../include/LVM2_PV_Info.h"
#include "../config.h"
2004-09-19 14:24:53 -06:00
#include <gtkmm/aboutdialog.h>
#include <gtkmm/messagedialog.h>
#include <gtkmm/radiobuttongroup.h>
#include <gtkmm/main.h>
#include <gtkmm/separator.h>
2004-09-19 14:24:53 -06:00
namespace GParted
{
Win_GParted::Win_GParted( const std::vector<Glib::ustring> & user_devices )
2004-09-19 14:24:53 -06:00
{
copied_partition = NULL;
selected_partition_ptr = NULL;
2004-09-19 14:24:53 -06:00
new_count = 1;
current_device = 0 ;
OPERATIONSLIST_OPEN = true ;
gparted_core .set_user_devices( user_devices ) ;
MENU_NEW = TOOLBAR_NEW =
MENU_DEL = TOOLBAR_DEL =
MENU_RESIZE_MOVE = TOOLBAR_RESIZE_MOVE =
MENU_COPY = TOOLBAR_COPY =
MENU_PASTE = TOOLBAR_PASTE =
MENU_FORMAT =
MENU_TOGGLE_BUSY =
MENU_MOUNT =
MENU_NAME_PARTITION =
MENU_FLAGS =
MENU_INFO =
MENU_LABEL_PARTITION =
MENU_CHANGE_UUID =
TOOLBAR_UNDO =
TOOLBAR_APPLY = -1 ;
2004-09-19 14:24:53 -06:00
//==== GUI =========================
this ->set_title( _("GParted") );
this ->set_default_size( 775, 500 );
try
{
#ifdef HAVE_SET_DEFAULT_ICON_NAME
this ->set_default_icon_name( "gparted" ) ;
#else
this ->set_icon_from_file( GNOME_ICONDIR "/gparted.png" ) ;
#endif
}
catch ( Glib::Exception & e )
{
std::cout << e .what() << std::endl ;
}
2004-09-19 14:24:53 -06:00
//Pack the main box
this ->add( vbox_main );
2004-09-19 14:24:53 -06:00
//menubar....
init_menubar() ;
2004-09-19 14:24:53 -06:00
vbox_main .pack_start( menubar_main, Gtk::PACK_SHRINK );
2004-09-19 14:24:53 -06:00
//toolbar....
init_toolbar() ;
2004-09-19 14:24:53 -06:00
vbox_main.pack_start( hbox_toolbar, Gtk::PACK_SHRINK );
//drawingarea_visualdisk... ( contains the visual represenation of the disks )
drawingarea_visualdisk .signal_partition_selected .connect(
sigc::mem_fun( this, &Win_GParted::on_partition_selected ) ) ;
drawingarea_visualdisk .signal_partition_activated .connect(
sigc::mem_fun( this, &Win_GParted::on_partition_activated ) ) ;
drawingarea_visualdisk .signal_popup_menu .connect(
sigc::mem_fun( this, &Win_GParted::on_partition_popup_menu ) );
vbox_main .pack_start( drawingarea_visualdisk, Gtk::PACK_SHRINK ) ;
2004-09-19 14:24:53 -06:00
//hpaned_main (NOTE: added to vpaned_main)
init_hpaned_main() ;
2004-09-19 14:24:53 -06:00
vpaned_main .pack1( hpaned_main, true, true ) ;
2004-09-19 14:24:53 -06:00
//vpaned_main....
vbox_main .pack_start( vpaned_main );
2004-09-19 14:24:53 -06:00
//device info...
init_device_info() ;
2004-09-19 14:24:53 -06:00
//operationslist...
hbox_operations .signal_undo .connect( sigc::mem_fun( this, &Win_GParted::activate_undo ) ) ;
hbox_operations .signal_clear .connect( sigc::mem_fun( this, &Win_GParted::clear_operationslist ) ) ;
hbox_operations .signal_apply .connect( sigc::mem_fun( this, &Win_GParted::activate_apply ) ) ;
hbox_operations .signal_close .connect( sigc::mem_fun( this, &Win_GParted::close_operationslist ) ) ;
2004-09-19 14:24:53 -06:00
vpaned_main .pack2( hbox_operations, true, true ) ;
//statusbar...
pulsebar .set_pulse_step( 0.01 );
statusbar .add( pulsebar );
vbox_main .pack_start( statusbar, Gtk::PACK_SHRINK );
this ->show_all_children();
//make sure harddisk information is closed..
hpaned_main .get_child1() ->hide() ;
2004-09-19 14:24:53 -06:00
}
Win_GParted::~Win_GParted()
{
delete copied_partition;
copied_partition = NULL;
}
void Win_GParted::init_menubar()
2004-09-19 14:24:53 -06:00
{
//fill menubar_main and connect callbacks
2004-09-19 14:24:53 -06:00
//gparted
menu = manage( new Gtk::Menu() ) ;
2004-09-19 14:24:53 -06:00
image = manage( new Gtk::Image( Gtk::Stock::REFRESH, Gtk::ICON_SIZE_MENU ) );
menu ->items() .push_back( Gtk::Menu_Helpers::ImageMenuElem(
_("_Refresh Devices"),
Gtk::AccelKey("<control>r"),
*image,
sigc::mem_fun(*this, &Win_GParted::menu_gparted_refresh_devices) ) );
image = manage( new Gtk::Image( Gtk::Stock::HARDDISK, Gtk::ICON_SIZE_MENU ) );
menu ->items() .push_back( Gtk::Menu_Helpers::ImageMenuElem( _("_Devices"), *image ) ) ;
menu ->items() .push_back( Gtk::Menu_Helpers::SeparatorElem( ) );
menu ->items() .push_back( Gtk::Menu_Helpers::StockMenuElem(
Gtk::Stock::QUIT, sigc::mem_fun(*this, &Win_GParted::menu_gparted_quit) ) );
menubar_main .items() .push_back( Gtk::Menu_Helpers::MenuElem( _("_GParted"), *menu ) );
//edit
menu = manage( new Gtk::Menu() ) ;
menu ->items() .push_back( Gtk::Menu_Helpers::ImageMenuElem(
_("_Undo Last Operation"),
Gtk::AccelKey("<control>z"),
* manage( new Gtk::Image( Gtk::Stock::UNDO, Gtk::ICON_SIZE_MENU ) ),
sigc::mem_fun(*this, &Win_GParted::activate_undo) ) );
menu ->items() .push_back( Gtk::Menu_Helpers::ImageMenuElem(
_("_Clear All Operations"),
* manage( new Gtk::Image( Gtk::Stock::CLEAR, Gtk::ICON_SIZE_MENU ) ),
sigc::mem_fun(*this, &Win_GParted::clear_operationslist) ) );
menu ->items() .push_back( Gtk::Menu_Helpers::ImageMenuElem(
_("_Apply All Operations"),
Gtk::AccelKey(GDK_Return, Gdk::CONTROL_MASK),
* manage( new Gtk::Image( Gtk::Stock::APPLY, Gtk::ICON_SIZE_MENU ) ),
sigc::mem_fun(*this, &Win_GParted::activate_apply) ) );
menubar_main .items() .push_back( Gtk::Menu_Helpers::MenuElem( _("_Edit"), *menu ) );
2004-09-27 14:12:47 -06:00
//view
menu = manage( new Gtk::Menu() ) ;
menu ->items() .push_back( Gtk::Menu_Helpers::CheckMenuElem(
_("Device _Information"), sigc::mem_fun(*this, &Win_GParted::menu_view_harddisk_info) ) );
menu ->items() .push_back( Gtk::Menu_Helpers::CheckMenuElem(
_("Pending _Operations"), sigc::mem_fun(*this, &Win_GParted::menu_view_operations) ) );
menubar_main .items() .push_back( Gtk::Menu_Helpers::MenuElem( _("_View"), *menu ) );
menu ->items() .push_back( Gtk::Menu_Helpers::SeparatorElem( ) );
menu ->items() .push_back( Gtk::Menu_Helpers::MenuElem(
_("_File System Support"), sigc::mem_fun( *this, &Win_GParted::menu_gparted_features ) ) );
//device
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
init_partition_menu() ;
menubar_main .items() .push_back( Gtk::Menu_Helpers::MenuElem( _("_Partition"), menu_partition ) );
2004-09-19 14:24:53 -06:00
//help
menu = manage( new Gtk::Menu() ) ;
menu ->items() .push_back( Gtk::Menu_Helpers::ImageMenuElem(
_("_Contents"),
Gtk::AccelKey("F1"),
* manage( new Gtk::Image( Gtk::Stock::HELP, Gtk::ICON_SIZE_MENU ) ),
sigc::mem_fun(*this, &Win_GParted::menu_help_contents) ) );
menu ->items() .push_back( Gtk::Menu_Helpers::SeparatorElem( ) );
menu ->items() .push_back( Gtk::Menu_Helpers::StockMenuElem(
Gtk::Stock::ABOUT, sigc::mem_fun(*this, &Win_GParted::menu_help_about) ) );
menubar_main.items() .push_back( Gtk::Menu_Helpers::MenuElem(_("_Help"), *menu ) );
2004-09-19 14:24:53 -06:00
}
void Win_GParted::init_toolbar()
2004-09-19 14:24:53 -06:00
{
int index = 0 ;
//initialize and pack toolbar_main
2004-09-19 14:24:53 -06:00
hbox_toolbar.pack_start( toolbar_main );
2004-09-19 14:24:53 -06:00
//NEW and DELETE
image = manage( new Gtk::Image( Gtk::Stock::NEW, Gtk::ICON_SIZE_BUTTON ) );
/*TO TRANSLATORS: "New" is a tool bar item for partition actions. */
Glib::ustring str_temp = _("New") ;
toolbutton = Gtk::manage(new Gtk::ToolButton( *image, str_temp ));
toolbutton ->signal_clicked() .connect( sigc::mem_fun( *this, &Win_GParted::activate_new ) );
toolbar_main .append( *toolbutton );
TOOLBAR_NEW = index++ ;
toolbutton ->set_tooltip(tooltips, _("Create a new partition in the selected unallocated space") );
2004-09-19 14:24:53 -06:00
toolbutton = Gtk::manage(new Gtk::ToolButton(Gtk::Stock::DELETE));
toolbutton ->signal_clicked().connect( sigc::mem_fun(*this, &Win_GParted::activate_delete) );
toolbar_main.append(*toolbutton);
TOOLBAR_DEL = index++ ;
toolbutton ->set_tooltip(tooltips, _("Delete the selected partition") );
2004-09-19 14:24:53 -06:00
toolbar_main.append( *(Gtk::manage(new Gtk::SeparatorToolItem)) );
index++ ;
2004-09-19 14:24:53 -06:00
//RESIZE/MOVE
image = manage( new Gtk::Image( Gtk::Stock::GOTO_LAST, Gtk::ICON_SIZE_BUTTON ) );
str_temp = _("Resize/Move") ;
//Condition string split and Undo button.
// for longer translated string, split string in two and skip the Undo button to permit full toolbar to display
// FIXME: Is there a better way to do this, perhaps without the conditional? At the moment this seems to be the best compromise.
bool display_undo = true ;
if( str_temp .length() > 14 ) {
size_t index = str_temp .find( "/" ) ;
if ( index != Glib::ustring::npos ) {
str_temp .replace( index, 1, "\n/" ) ;
display_undo = false ;
}
}
toolbutton = Gtk::manage(new Gtk::ToolButton( *image, str_temp ));
toolbutton ->signal_clicked().connect( sigc::mem_fun(*this, &Win_GParted::activate_resize) );
toolbar_main.append(*toolbutton);
TOOLBAR_RESIZE_MOVE = index++ ;
toolbutton ->set_tooltip(tooltips, _("Resize/Move the selected partition") );
2004-09-19 14:24:53 -06:00
toolbar_main.append( *(Gtk::manage(new Gtk::SeparatorToolItem)) );
index++ ;
2004-09-19 14:24:53 -06:00
//COPY and PASTE
toolbutton = Gtk::manage(new Gtk::ToolButton(Gtk::Stock::COPY));
toolbutton ->signal_clicked().connect( sigc::mem_fun(*this, &Win_GParted::activate_copy) );
toolbar_main.append(*toolbutton);
TOOLBAR_COPY = index++ ;
toolbutton ->set_tooltip(tooltips, _("Copy the selected partition to the clipboard") );
2004-09-19 14:24:53 -06:00
toolbutton = Gtk::manage(new Gtk::ToolButton(Gtk::Stock::PASTE));
toolbutton ->signal_clicked().connect( sigc::mem_fun(*this, &Win_GParted::activate_paste) );
toolbar_main.append(*toolbutton);
TOOLBAR_PASTE = index++ ;
toolbutton ->set_tooltip(tooltips, _("Paste the partition from the clipboard") );
2004-09-19 14:24:53 -06:00
toolbar_main.append( *(Gtk::manage(new Gtk::SeparatorToolItem)) );
index++ ;
2004-09-19 14:24:53 -06:00
//UNDO and APPLY
if ( display_undo ) {
//Undo button is displayed only if translated language "Resize/Move" is not too long. See above setting of this condition.
toolbutton = Gtk::manage(new Gtk::ToolButton(Gtk::Stock::UNDO));
toolbutton ->signal_clicked().connect( sigc::mem_fun(*this, &Win_GParted::activate_undo) );
toolbar_main.append(*toolbutton);
TOOLBAR_UNDO = index++ ;
toolbutton ->set_sensitive( false );
toolbutton ->set_tooltip(tooltips, _("Undo Last Operation") );
}
2004-09-19 14:24:53 -06:00
toolbutton = Gtk::manage(new Gtk::ToolButton(Gtk::Stock::APPLY));
toolbutton ->signal_clicked().connect( sigc::mem_fun(*this, &Win_GParted::activate_apply) );
toolbar_main.append(*toolbutton);
TOOLBAR_APPLY = index++ ;
toolbutton ->set_sensitive( false );
toolbutton ->set_tooltip(tooltips, _("Apply All Operations") );
//initialize and pack combo_devices
liststore_devices = Gtk::ListStore::create( treeview_devices_columns ) ;
combo_devices .set_model( liststore_devices ) ;
combo_devices .pack_start( treeview_devices_columns .icon, false ) ;
combo_devices .pack_start( treeview_devices_columns .device ) ;
combo_devices .pack_start( treeview_devices_columns .size, false ) ;
Prevent flashing redraw of the devices combobox (#696149) The device combobox was getting drawn blank, then getting drawn again with the selected device. This was happening because at the start of Win_GParted::refresh_combo_devices() the GTK model behind the combobox, liststore_devices, was cleared, changing the active item, causing the combobox to get redrawn empty. After the GTK model had been repopulated the active item was reset causing the comboxbox to get redrawn again, now showing the selected device. Call flow: Win_GParted::refresh_combo_devices() liststore_devices->clear() //Gtk::Combobox emits signal_change. Registered callbacks //called. Win_GParted::combo_devices_changed() Win_GParted::Refresh_Visual() ... ... combo_devices.set_active(current_device); //Gtk::Combobox emits signal_change. Registered callbacks //called. Win_GParted::combo_devices_changed() Win_GParted::Refresh_Visual() ... This has always been the case, since the device combobox was first added to GParted before version 0.1 by commit: 3a4b43e0adb3974dea656fcbe90d5e191e0e9784 replaced deprecated OptionMenu with ComboBox ... Fix by temporarily blocking the devices comboxbox from emitting signal_changed while the GTK model behind the combobox is recreated. However, since automatic selection of the largest free space was added [1] in GParted 0.15.0, a more noticeable flashing redraw issue was caused in which the partition graphic and partition list were both drawn blank then redrawn fully populated. Some distributions were not affected by this at all, some only experienced a single flash and others suffered from two or more flashing redraws. Some affected distributions: CentOS 5.10, 6.5, 7.0, Debian 6, Fedora 14, 19, 20, Ubuntu 13.10, Xubuntu 14.04 LTS. Did not occur on Kubuntu 12.04 LTS. [1] 5b53c12f6ee12312a9bacb44b8b05b12a540d3d6 Select largest unallocated partition by default (#667365) Bug #696149 - Double refresh of display introduced with default unallocated space
2014-08-22 04:35:39 -06:00
combo_devices_changed_connection =
combo_devices .signal_changed() .connect( sigc::mem_fun(*this, &Win_GParted::combo_devices_changed) );
hbox_toolbar .pack_start( combo_devices, Gtk::PACK_SHRINK ) ;
2004-09-19 14:24:53 -06:00
}
void Win_GParted::init_partition_menu()
2004-09-19 14:24:53 -06:00
{
int index = 0 ;
//fill menu_partition
image = manage( new Gtk::Image( Gtk::Stock::NEW, Gtk::ICON_SIZE_MENU ) );
menu_partition .items() .push_back(
/*TO TRANSLATORS: "_New" is a sub menu item for the partition menu. */
Gtk::Menu_Helpers::ImageMenuElem( _("_New"),
Gtk::AccelKey( GDK_Insert, Gdk::BUTTON1_MASK),
*image,
sigc::mem_fun(*this, &Win_GParted::activate_new) ) );
MENU_NEW = index++ ;
menu_partition .items() .push_back(
Gtk::Menu_Helpers::StockMenuElem( Gtk::Stock::DELETE,
Gtk::AccelKey( GDK_Delete, Gdk::BUTTON1_MASK ),
sigc::mem_fun(*this, &Win_GParted::activate_delete) ) );
MENU_DEL = index++ ;
menu_partition .items() .push_back( Gtk::Menu_Helpers::SeparatorElem() );
index++ ;
2004-09-19 14:24:53 -06:00
image = manage( new Gtk::Image( Gtk::Stock::GOTO_LAST, Gtk::ICON_SIZE_MENU ) );
menu_partition .items() .push_back(
Gtk::Menu_Helpers::ImageMenuElem( _("_Resize/Move"),
*image,
sigc::mem_fun(*this, &Win_GParted::activate_resize) ) );
MENU_RESIZE_MOVE = index++ ;
menu_partition .items() .push_back( Gtk::Menu_Helpers::SeparatorElem() );
index++ ;
menu_partition .items() .push_back(
Gtk::Menu_Helpers::StockMenuElem( Gtk::Stock::COPY,
sigc::mem_fun(*this, &Win_GParted::activate_copy) ) );
MENU_COPY = index++ ;
menu_partition .items() .push_back(
Gtk::Menu_Helpers::StockMenuElem( Gtk::Stock::PASTE,
sigc::mem_fun(*this, &Win_GParted::activate_paste) ) );
MENU_PASTE = index++ ;
menu_partition .items() .push_back( Gtk::Menu_Helpers::SeparatorElem() );
index++ ;
2004-09-19 14:24:53 -06:00
image = manage( new Gtk::Image( Gtk::Stock::CONVERT, Gtk::ICON_SIZE_MENU ) );
/*TO TRANSLATORS: menuitem which holds a submenu with file systems.. */
menu_partition .items() .push_back(
Gtk::Menu_Helpers::ImageMenuElem( _("_Format to"),
*image,
* create_format_menu() ) ) ;
MENU_FORMAT = index++ ;
menu_partition .items() .push_back( Gtk::Menu_Helpers::SeparatorElem() ) ;
index++ ;
menu_partition .items() .push_back(
//This is a placeholder text. It will be replaced with some other text before it is used
Gtk::Menu_Helpers::MenuElem( "--placeholder--",
sigc::mem_fun( *this, &Win_GParted::toggle_busy_state ) ) );
MENU_TOGGLE_BUSY = index++ ;
/*TO TRANSLATORS: menuitem which holds a submenu with mount points.. */
menu_partition .items() .push_back(
Gtk::Menu_Helpers::MenuElem( _("_Mount on"), * manage( new Gtk::Menu() ) ) ) ;
MENU_MOUNT = index++ ;
menu_partition .items() .push_back( Gtk::Menu_Helpers::SeparatorElem() ) ;
index++ ;
menu_partition.items().push_back(
Gtk::Menu_Helpers::MenuElem( _("_Name Partition"),
sigc::mem_fun( *this, &Win_GParted::activate_name_partition ) ) );
MENU_NAME_PARTITION = index++;
menu_partition .items() .push_back(
Gtk::Menu_Helpers::MenuElem( _("M_anage Flags"),
sigc::mem_fun( *this, &Win_GParted::activate_manage_flags ) ) );
MENU_FLAGS = index++ ;
menu_partition .items() .push_back(
Gtk::Menu_Helpers::MenuElem( _("C_heck"),
sigc::mem_fun( *this, &Win_GParted::activate_check ) ) );
MENU_CHECK = index++ ;
menu_partition .items() .push_back(
Gtk::Menu_Helpers::MenuElem( _("_Label File System"),
sigc::mem_fun( *this, &Win_GParted::activate_label_filesystem ) ) );
MENU_LABEL_PARTITION = index++ ;
menu_partition .items() .push_back(
Gtk::Menu_Helpers::MenuElem( _("New UU_ID"),
sigc::mem_fun( *this, &Win_GParted::activate_change_uuid ) ) );
MENU_CHANGE_UUID = index++ ;
menu_partition .items() .push_back( Gtk::Menu_Helpers::SeparatorElem() ) ;
index++ ;
menu_partition .items() .push_back(
Gtk::Menu_Helpers::StockMenuElem( Gtk::Stock::DIALOG_INFO,
sigc::mem_fun(*this, &Win_GParted::activate_info) ) );
MENU_INFO = index++ ;
menu_partition .accelerate( *this ) ;
2004-09-19 14:24:53 -06:00
}
//Create the Partition --> Format to --> (file system list) menu
Gtk::Menu * Win_GParted::create_format_menu()
2004-09-19 14:24:53 -06:00
{
const std::vector<FS> & fss = gparted_core .get_filesystems() ;
menu = manage( new Gtk::Menu() ) ;
for ( unsigned int t = 0 ; t < fss .size() ; t++ )
2004-09-19 14:24:53 -06:00
{
if ( GParted_Core::supported_filesystem( fss[t].filesystem ) &&
fss[t].filesystem != FS_LUKS )
create_format_menu_add_item( fss[t].filesystem, fss[t].create );
2004-09-19 14:24:53 -06:00
}
//Add cleared at the end of the list
create_format_menu_add_item( FS_CLEARED, true ) ;
return menu ;
2004-09-19 14:24:53 -06:00
}
//Add one entry to the Partition --> Format to --> (file system list) menu
void Win_GParted::create_format_menu_add_item( FILESYSTEM filesystem, bool activate )
{
hbox = manage( new Gtk::HBox() ) ;
//the colored square
hbox ->pack_start( * manage( new Gtk::Image( Utils::get_color_as_pixbuf( filesystem, 16, 16 ) ) ),
Gtk::PACK_SHRINK ) ;
//the label...
hbox ->pack_start( * Utils::mk_label( " " + Utils::get_filesystem_string( filesystem ) ),
Gtk::PACK_SHRINK ) ;
menu ->items() .push_back( * manage( new Gtk::MenuItem( *hbox ) ) ) ;
if ( activate )
menu ->items() .back() .signal_activate() .connect(
sigc::bind<GParted::FILESYSTEM>( sigc::mem_fun( *this, &Win_GParted::activate_format ),
filesystem ) ) ;
else
menu ->items() .back() .set_sensitive( false ) ;
}
2004-09-19 14:24:53 -06:00
void Win_GParted::init_device_info()
{
vbox_info.set_spacing( 5 );
2006-03-28 05:40:29 -07:00
int top = 0, bottom = 1;
//title
vbox_info .pack_start(
* Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Device Information") ) + "</b>" ),
2006-03-28 05:40:29 -07:00
Gtk::PACK_SHRINK );
//GENERAL DEVICE INFO
2004-09-19 14:24:53 -06:00
table = manage( new Gtk::Table() ) ;
table ->set_col_spacings( 10 ) ;
//model
2006-03-28 05:40:29 -07:00
table ->attach( * Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Model:") ) + "</b>" ),
0, 1,
top, bottom,
Gtk::FILL ) ;
device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
2006-03-28 05:40:29 -07:00
table ->attach( * device_info .back(), 1, 2, top++, bottom++, Gtk::FILL ) ;
// Serial number
table->attach( *Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Serial:") ) + "</b>" ),
0, 1, top, bottom, Gtk::FILL );
device_info.push_back( Utils::mk_label( "", true, false, true ) );
table->attach( *device_info.back(), 1, 2, top++, bottom++, Gtk::FILL );
//size
2006-03-28 05:40:29 -07:00
table ->attach( * Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Size:") ) + "</b>" ),
0, 1,
top, bottom,
Gtk::FILL ) ;
device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
2006-03-28 05:40:29 -07:00
table ->attach( * device_info .back(), 1, 2, top++, bottom++, Gtk::FILL ) ;
//path
table ->attach( * Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Path:") ) + "</b>" ),
2006-03-28 05:40:29 -07:00
0, 1,
top, bottom,
Gtk::FILL ) ;
device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
2006-03-28 05:40:29 -07:00
table ->attach( * device_info .back(), 1, 2, top++, bottom++, Gtk::FILL ) ;
vbox_info .pack_start( *table, Gtk::PACK_SHRINK );
//DETAILED DEVICE INFO
2006-03-28 05:40:29 -07:00
top = 0 ; bottom = 1;
table = manage( new Gtk::Table() ) ;
table ->set_col_spacings( 10 ) ;
//one blank line
table ->attach( * Utils::mk_label( "" ), 1, 2, top++, bottom++, Gtk::FILL );
//disktype
table ->attach( * Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Partition table:") ) + "</b>" ),
2006-03-28 05:40:29 -07:00
0, 1,
top, bottom,
Gtk::FILL );
device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
2006-03-28 05:40:29 -07:00
table ->attach( * device_info .back(), 1, 2, top++, bottom++, Gtk::FILL ) ;
//heads
2006-03-28 05:40:29 -07:00
table ->attach( * Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Heads:") ) + "</b>" ),
0, 1,
top, bottom,
Gtk::FILL ) ;
device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
2006-03-28 05:40:29 -07:00
table ->attach( * device_info .back(), 1, 2, top++, bottom++, Gtk::FILL ) ;
//sectors/track
table ->attach( * Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Sectors/track:") ) + "</b>" ),
2006-03-28 05:40:29 -07:00
0, 1,
top, bottom,
Gtk::FILL ) ;
device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
2006-03-28 05:40:29 -07:00
table ->attach( * device_info .back(), 1, 2, top++, bottom++, Gtk::FILL );
//cylinders
2006-03-28 05:40:29 -07:00
table ->attach( * Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Cylinders:") ) + "</b>" ),
0, 1,
top, bottom,
Gtk::FILL ) ;
device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
2006-03-28 05:40:29 -07:00
table ->attach( * device_info .back(), 1, 2, top++, bottom++, Gtk::FILL ) ;
//total sectors
table ->attach( * Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Total sectors:") ) + "</b>" ),
2006-03-28 05:40:29 -07:00
0, 1,
top, bottom,
Gtk::FILL );
device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
2006-03-28 05:40:29 -07:00
table ->attach( * device_info .back(), 1, 2, top++, bottom++, Gtk::FILL ) ;
//sector size
table ->attach( * Utils::mk_label( " <b>" + static_cast<Glib::ustring>( _("Sector size:") ) + "</b>" ),
0, 1,
top, bottom,
Gtk::FILL );
device_info .push_back( Utils::mk_label( "", true, false, true ) ) ;
table ->attach( * device_info .back(), 1, 2, top++, bottom++, Gtk::FILL ) ;
vbox_info .pack_start( *table, Gtk::PACK_SHRINK );
2004-09-19 14:24:53 -06:00
}
void Win_GParted::init_hpaned_main()
2004-09-19 14:24:53 -06:00
{
//left scrollwindow (holds device info)
scrollwindow = manage( new Gtk::ScrolledWindow() ) ;
scrollwindow ->set_shadow_type( Gtk::SHADOW_ETCHED_IN );
scrollwindow ->set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC );
2004-09-19 14:24:53 -06:00
hpaned_main .pack1( *scrollwindow, true, true );
2004-09-19 14:24:53 -06:00
scrollwindow ->add( vbox_info );
//right scrollwindow (holds treeview with partitions)
scrollwindow = manage( new Gtk::ScrolledWindow() ) ;
scrollwindow ->set_shadow_type( Gtk::SHADOW_ETCHED_IN );
scrollwindow ->set_policy( Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC );
//connect signals and add treeview_detail
treeview_detail .signal_partition_selected .connect( sigc::mem_fun( this, &Win_GParted::on_partition_selected ) );
treeview_detail .signal_partition_activated .connect( sigc::mem_fun( this, &Win_GParted::on_partition_activated ) );
treeview_detail .signal_popup_menu .connect( sigc::mem_fun( this, &Win_GParted::on_partition_popup_menu ) );
scrollwindow ->add( treeview_detail );
hpaned_main .pack2( *scrollwindow, true, true );
2004-09-19 14:24:53 -06:00
}
void Win_GParted::refresh_combo_devices()
{
Prevent flashing redraw of the devices combobox (#696149) The device combobox was getting drawn blank, then getting drawn again with the selected device. This was happening because at the start of Win_GParted::refresh_combo_devices() the GTK model behind the combobox, liststore_devices, was cleared, changing the active item, causing the combobox to get redrawn empty. After the GTK model had been repopulated the active item was reset causing the comboxbox to get redrawn again, now showing the selected device. Call flow: Win_GParted::refresh_combo_devices() liststore_devices->clear() //Gtk::Combobox emits signal_change. Registered callbacks //called. Win_GParted::combo_devices_changed() Win_GParted::Refresh_Visual() ... ... combo_devices.set_active(current_device); //Gtk::Combobox emits signal_change. Registered callbacks //called. Win_GParted::combo_devices_changed() Win_GParted::Refresh_Visual() ... This has always been the case, since the device combobox was first added to GParted before version 0.1 by commit: 3a4b43e0adb3974dea656fcbe90d5e191e0e9784 replaced deprecated OptionMenu with ComboBox ... Fix by temporarily blocking the devices comboxbox from emitting signal_changed while the GTK model behind the combobox is recreated. However, since automatic selection of the largest free space was added [1] in GParted 0.15.0, a more noticeable flashing redraw issue was caused in which the partition graphic and partition list were both drawn blank then redrawn fully populated. Some distributions were not affected by this at all, some only experienced a single flash and others suffered from two or more flashing redraws. Some affected distributions: CentOS 5.10, 6.5, 7.0, Debian 6, Fedora 14, 19, 20, Ubuntu 13.10, Xubuntu 14.04 LTS. Did not occur on Kubuntu 12.04 LTS. [1] 5b53c12f6ee12312a9bacb44b8b05b12a540d3d6 Select largest unallocated partition by default (#667365) Bug #696149 - Double refresh of display introduced with default unallocated space
2014-08-22 04:35:39 -06:00
// Temporarily block the on change callback while re-creating the device list
// behind the combobox to prevent flashing redraw by being redrawn with an empty
// device list.
combo_devices_changed_connection .block();
liststore_devices ->clear() ;
menu = manage( new Gtk::Menu() ) ;
Gtk::RadioButtonGroup radio_group ;
for ( unsigned int i = 0 ; i < devices .size( ) ; i++ )
{
//combo...
treerow = *( liststore_devices ->append() ) ;
treerow[ treeview_devices_columns .icon ] =
render_icon( Gtk::Stock::HARDDISK, Gtk::ICON_SIZE_LARGE_TOOLBAR ) ;
treerow[ treeview_devices_columns .device ] = devices[ i ] .get_path() ;
treerow[ treeview_devices_columns .size ] = "(" + Utils::format_size( devices[ i ] .length, devices[ i ] .sector_size ) + ")" ;
//devices submenu....
hbox = manage( new Gtk::HBox() ) ;
hbox ->pack_start( * Utils::mk_label( devices[ i ] .get_path() ), Gtk::PACK_EXPAND_WIDGET ) ;
hbox ->pack_start( * Utils::mk_label( " (" + Utils::format_size( devices[ i ] .length, devices[ i ] .sector_size ) + ")" ),
Gtk::PACK_SHRINK ) ;
menu ->items() .push_back( * manage( new Gtk::RadioMenuItem( radio_group ) ) ) ;
menu ->items() .back() .add( *hbox ) ;
menu ->items() .back() .signal_activate() .connect(
sigc::bind<unsigned int>( sigc::mem_fun(*this, &Win_GParted::radio_devices_changed), i ) ) ;
2004-09-19 14:24:53 -06:00
}
menubar_main .items()[ 0 ] .get_submenu() ->items()[ 1 ] .remove_submenu() ;
if ( menu ->items() .size() )
{
menu ->show_all() ;
menubar_main .items()[ 0 ] .get_submenu() ->items()[ 1 ] .set_submenu( *menu ) ;
}
Prevent flashing redraw of the devices combobox (#696149) The device combobox was getting drawn blank, then getting drawn again with the selected device. This was happening because at the start of Win_GParted::refresh_combo_devices() the GTK model behind the combobox, liststore_devices, was cleared, changing the active item, causing the combobox to get redrawn empty. After the GTK model had been repopulated the active item was reset causing the comboxbox to get redrawn again, now showing the selected device. Call flow: Win_GParted::refresh_combo_devices() liststore_devices->clear() //Gtk::Combobox emits signal_change. Registered callbacks //called. Win_GParted::combo_devices_changed() Win_GParted::Refresh_Visual() ... ... combo_devices.set_active(current_device); //Gtk::Combobox emits signal_change. Registered callbacks //called. Win_GParted::combo_devices_changed() Win_GParted::Refresh_Visual() ... This has always been the case, since the device combobox was first added to GParted before version 0.1 by commit: 3a4b43e0adb3974dea656fcbe90d5e191e0e9784 replaced deprecated OptionMenu with ComboBox ... Fix by temporarily blocking the devices comboxbox from emitting signal_changed while the GTK model behind the combobox is recreated. However, since automatic selection of the largest free space was added [1] in GParted 0.15.0, a more noticeable flashing redraw issue was caused in which the partition graphic and partition list were both drawn blank then redrawn fully populated. Some distributions were not affected by this at all, some only experienced a single flash and others suffered from two or more flashing redraws. Some affected distributions: CentOS 5.10, 6.5, 7.0, Debian 6, Fedora 14, 19, 20, Ubuntu 13.10, Xubuntu 14.04 LTS. Did not occur on Kubuntu 12.04 LTS. [1] 5b53c12f6ee12312a9bacb44b8b05b12a540d3d6 Select largest unallocated partition by default (#667365) Bug #696149 - Double refresh of display introduced with default unallocated space
2014-08-22 04:35:39 -06:00
combo_devices_changed_connection .unblock();
combo_devices .set_active( current_device ) ;
}
bool Win_GParted::pulsebar_pulse()
{
pulsebar.pulse();
Glib::ustring tmp_msg = gparted_core .get_thread_status_message() ;
if ( tmp_msg != "" ) {
statusbar.pop();
statusbar.push( tmp_msg );
}
return true;
}
void Win_GParted::show_pulsebar( const Glib::ustring & status_message )
{
pulsebar .show();
statusbar .push( status_message) ;
//disable all input stuff
toolbar_main .set_sensitive( false ) ;
menubar_main .set_sensitive( false ) ;
combo_devices .set_sensitive( false ) ;
menu_partition .set_sensitive( false ) ;
treeview_detail .set_sensitive( false ) ;
drawingarea_visualdisk .set_sensitive( false ) ;
// connect pulse update timer
pulsetimer = Glib::signal_timeout().connect( sigc::mem_fun(*this, &Win_GParted::pulsebar_pulse), 100 );
}
void Win_GParted::hide_pulsebar()
{
pulsetimer.disconnect();
pulsebar .hide();
statusbar .pop() ;
//enable all disabled stuff
toolbar_main .set_sensitive( true ) ;
menubar_main .set_sensitive( true ) ;
combo_devices .set_sensitive( true ) ;
menu_partition .set_sensitive( true ) ;
treeview_detail .set_sensitive( true ) ;
drawingarea_visualdisk .set_sensitive( true ) ;
2004-09-19 14:24:53 -06:00
}
void Win_GParted::Fill_Label_Device_Info( bool clear )
2004-09-19 14:24:53 -06:00
{
if ( clear )
for ( unsigned int t = 0 ; t < device_info .size( ) ; t++ )
device_info[ t ] ->set_text( "" ) ;
else
{
short t = 0;
//global info...
device_info[ t++ ] ->set_text( devices[ current_device ] .model ) ;
device_info[ t++ ] ->set_text( devices[current_device].serial_number );
device_info[ t++ ] ->set_text( Utils::format_size( devices[ current_device ] .length, devices[ current_device ] .sector_size ) ) ;
Simplify Device object to a single path (#767842) Background GParted stored a list of paths for Device and Partition objects. It sorted this list [1][2] and treated the first specially as that is what get_path() returned and was used almost everywhere; with the file system specific tools, looked up in various *_Info caches, etc. [1] Device::add_path(), ::add_paths() [2] Partition::add_path(), ::add_paths() Mount point display [3] was the only bit of GParted which really worked with the path list. Busy file system detection [4] just used the path provided by libparted, or for LUKS /dev/mapper/* names. It checked that single path against the mounted file systems found from /proc/mounts, expanded with additional block device names when symlinks were encountered. [3] GParted_Core::set_mountpoints() -> set_mountpoints_helper() [4] GParted_Core::set_device_partitions() -> is_busy() GParted_Core::set_device_one_partition() -> is_busy() GParted_Core::set_luks_partition() -> is_busy() Having the first path, by sort order, treated specially by being used everywhere and virtually ignoring the others was wrong, complicated to remember and difficult code with. As all the additional paths were virtually unused and made no difference, remove them. The "improved detection of mountpoins, free space, etc.." benefit from commit [5] doesn't seem to exist. Therefore simplify to a single path for Device and Partition objects. [5] commit 6d8b169e734e1ecb191d5164689f24400010a7b4 changed the way devices and partitions store their device paths. Instead of holding a 'realpath' and a symbolic path we store paths in a list. This allows for improved detection of mountpoins, free space, etc.. This patch Simplify the Device object from a vector of paths to a single path. Remove add_paths() and get_paths() methods. Keep add_path() and get_path() for now. Bug 767842 - File system usage missing when tools report alternate block device names
2016-06-02 00:49:53 -06:00
device_info[ t++ ] ->set_text( devices[current_device].get_path() );
//detailed info
device_info[ t++ ] ->set_text( devices[ current_device ] .disktype ) ;
device_info[ t++ ] ->set_text( Utils::num_to_str( devices[ current_device ] .heads ) );
device_info[ t++ ] ->set_text( Utils::num_to_str( devices[ current_device ] .sectors ) );
device_info[ t++ ] ->set_text( Utils::num_to_str( devices[ current_device ] .cylinders ) );
device_info[ t++ ] ->set_text( Utils::num_to_str( devices[ current_device ] .length ) );
device_info[ t++ ] ->set_text( Utils::num_to_str( devices[ current_device ] .sector_size ) );
}
2004-09-19 14:24:53 -06:00
}
bool Win_GParted::on_delete_event( GdkEventAny *event )
2004-09-19 14:24:53 -06:00
{
return ! Quit_Check_Operations();
}
2004-09-19 14:24:53 -06:00
void Win_GParted::Add_Operation( Operation * operation )
2004-09-19 14:24:53 -06:00
{
if ( operation )
{
Glib::ustring error ;
Fix uninitialised read when pasting into an existing partition GParted_Core::set_device_partitions() creates and initialises the partition objects based on the partitions on the disk using partition.Reset() and partition.Set(). These methods never set the alignment attribute. Copy and pasting into an existing partition calls GParted_Core:: snap_to_alignment() to adjust the start and end of the newly created in memory partition object. When pasting into unallocated space the user has selected the required alignment and this is exactly what is needed. However when pasting into an existing partition the in memory partition object should always match the actual partition boundaries on disk. Unfortunately the partition boundaries are adjusted based on reading the uninitialised alignment attribute. Initialise the alignment attribute of newly created partition objects to ALIGN_STRICT. Also, when pasting into an existing partition set the alignment of that partition object to ALIGN_STRICT so that no boundary adjustment is performed. valgrind: ==6845== Conditional jump or move depends on uninitialised value(s) ==6845== at 0x80C779A: GParted::GParted_Core::snap_to_alignment(...) (GParted_Core.cc:566) ==6845== by 0x810C115: GParted::Win_GParted::Add_Operation(...) (Win_GParted.cc:692) ==6845== by 0x8110499: GParted::Win_GParted::activate_paste() (Win_GParted.cc:1649) ... ==6845== Conditional jump or move depends on uninitialised value(s) ==6845== at 0x80C77A8: GParted::GParted_Core::snap_to_alignment(...) (GParted_Core.cc:568) ==6845== by 0x810C115: GParted::Win_GParted::Add_Operation(...) (Win_GParted.cc:692) ==6845== by 0x8110499: GParted::Win_GParted::activate_paste() (Win_GParted.cc:1649) GParted_Core.cc: 562 bool GParted_Core::snap_to_alignment( const Device & device, Partition & partition, Glib::ustring & error ) 563 { 564 bool rc = true ; 565 >> 566 if ( partition .alignment == ALIGN_CYLINDER ) 567 rc = snap_to_cylinder( device, partition, error ) ; >> 568 else if ( partition .alignment == ALIGN_MEBIBYTE ) 569 rc = snap_to_mebibyte( device, partition, error ) ; 570 Closes Bug #672654 - Pasting into an existing partition may shrink GParted's representation of it
2012-03-23 09:51:08 -06:00
//Add any of the listed operations without further checking, but
// for the other operations (_CREATE, _RESIZE_MOVE and _COPY)
// ensure the partition is correctly aligned.
//FIXME: this is becoming a mess.. maybe it's better to check if partition_new > 0
if ( operation ->type == OPERATION_DELETE ||
operation ->type == OPERATION_FORMAT ||
operation ->type == OPERATION_CHECK ||
operation ->type == OPERATION_CHANGE_UUID ||
operation ->type == OPERATION_LABEL_FILESYSTEM ||
operation ->type == OPERATION_NAME_PARTITION ||
gparted_core.snap_to_alignment( operation->device, operation->get_partition_new(), error )
)
{
operation ->create_description() ;
operations.push_back( operation );
}
else
{
Gtk::MessageDialog dialog( *this,
_("Could not add this operation to the list"),
false,
Gtk::MESSAGE_ERROR,
Gtk::BUTTONS_OK,
true );
dialog .set_secondary_text( error ) ;
dialog .run() ;
}
}
2004-09-19 14:24:53 -06:00
}
// Try to merge the second operation into the first in the operations[] vector.
bool Win_GParted::merge_two_operations( unsigned int first, unsigned int second )
{
unsigned int num_ops = operations.size();
if ( first >= num_ops-1 )
return false;
if ( first >= second || second >= num_ops )
return false;
if ( operations[first]->merge_operations( *operations[second] ) )
{
remove_operation( second );
return true;
}
return false;
}
// Try to merge pending operations in the operations[] vector using the specified merge
// type.
//
// Summary of all the operation merging rules for each operation type coded into the
// ::activate_*() methods:
//
// Operation type Partition status Merge type Method
// ----------------- ---------------- -------------------- -----------------
// resize/move Real MERGE_LAST_WITH_PREV activate_resize()
// resize/move New MERGE_LAST_WITH_ANY activate_resize()
// paste * none activate_paste()
// new * none activate_new()
// delete Real none activate_delete()
// delete New MERGE_ALL_ADJACENT activate_delete()
// format Real MERGE_LAST_WITH_PREV activate_format()
// format New MERGE_LAST_WITH_ANY activate_format()
// check Real [1] MERGE_LAST_WITH_ANY activate_check()
// label file system Real [1] MERGE_LAST_WITH_ANY activate_label_filesystem()
// name partition Real [1] MERGE_LAST_WITH_ANY activate_name_partition()
// new UUID Real [1] MERGE_LAST_WITH_ANY activate_change_uuid()
//
// [1] The UI only allows these operations to be applied to real partitions; where as the
// other mergeable operations can be applied to both real partitions and new, pending
// create partitions.
void Win_GParted::merge_operations( MergeType mergetype )
{
unsigned int num_ops = operations.size();
if ( num_ops <= 1 )
return; // Nothing to merge. One or fewer operations.
switch ( mergetype )
{
case MERGE_LAST_WITH_PREV:
merge_two_operations( num_ops-2, num_ops-1 );
break;
case MERGE_LAST_WITH_ANY:
for ( unsigned int i = 0 ; i < num_ops-1 ; i ++ )
{
if ( merge_two_operations( i, num_ops-1 ) )
break;
}
break;
case MERGE_ALL_ADJACENT:
// Must check against operations.size() as looping continues after
// merging which might have reduced the number of items in the
// vector.
for ( unsigned int i = 0 ; i < operations.size()-1 ; i ++ )
{
merge_two_operations( i, i+1 );
}
break;
}
}
void Win_GParted::Refresh_Visual()
2004-09-19 14:24:53 -06:00
{
// How GParted displays partitions in the GUI and manages the lifetime and
// ownership of that data:
//
// (1) Queries the devices and partitions on disk and refreshes the model.
//
// Data owner: std::vector<Devices> Win_GParted::devices
// Lifetime: Valid until the next call to Refresh_Visual()
// Call chain:
//
// Win_GParted::menu_gparted_refresh_devices()
// gparted_core.set_devices( devices )
// GParted_Core::set_devices_thread( devices )
// devices.clear()
// etc.
//
// (2) Takes a copy of the partitions for the device currently being shown in the
// GUI and visually applies pending operations.
//
// Data owner: PartitionVector Win_GParted::display_partitions
// Lifetime: Valid until the next call to Refresh_Visual().
// Function: Refresh_Visual()
//
// (3) Loads the disk graphic and partition list with partitions to be shown in
// the GUI. Both classes store pointers pointing back to each partition
// object in the vector of display partitions.
//
// Aliases: Win_GParted::display_partitions[]
// Call chain:
//
// Win_GParted::Refresh_Visual()
// drawingarea_visualdisk.load_partitions( display_partitions, device_sectors )
// DrawingAreaVisualDisk::set_static_data( ... )
// treeview_detail.load_partitions( display_partitions )
// TreeView_Detail::create_row()
// TreeView_Detail::load_partitions()
// TreeView_Detail::create_row()
//
// (4) Selecting a partition in the disk graphic or in the partition list fires
// the callback which passes a pointer to the selected partition stored in
// step (3). The callback saves the selected partition and calls the opposite
// class to update it's selection.
//
// Data owner: const Partition * Win_GParted::selected_partition_ptr
// Aliases: Win_GParted::display_partitions[]
// Lifetime: Valid until the next call to Refresh_Visual().
// Call chain: (example clicking on a partition in the disk graphic)
//
// DrawingAreaVisualDisk::on_button_press_event()
// DawingAreaVisualDisk::set_selected( visual_partitions, x, y )
// signal_partition_selected.emit( ..., false )
// Win_GParted::on_partition_selected( partition_ptr, src_is_treeview )
// treeview_detail.set_selected( treestore_detail->children(), partition_ptr )
// TreeView::set_selected( rows, partition_ptr, inside_extended )
// set_cursor()
// TreeView::set_selected( rows, partition_ptr, true )
// set_cursor()
//
// (5) Each new operation is added to the vector of pending operations.
// Eventually Refresh_Visual() is call to update the GUI. This goes to step
// (2) which visually reapplies all pending operations again, including the
// newly added operation.
//
// Data owner: std::vector<Operation *> Win_GParted::operations
// Lifetime: Valid until operations have been applied by
// GParted_Core::apply_operation_to_disk(). Specifically longer
// than the next call call to Refresh_Visual().
// Call chain: (example setting a file system label)
//
// Win_GParted::activate_label_filesystem()
// Win_GParted::Add_Operation( operation )
// Win_GParted::merge_operations( ... )
// Win_GParted::show_operationslist()
// Win_GParted::Refresh_Visual()
//
// (6) Selecting a partition as a copy source makes a copy of that partition
// object.
//
// Data owner: Partition Win_GParted::copied_partition
// Lifetime: Valid until GParted closed or the device is removed.
// Specifically longer than the next call to Refresh_Visual().
// Function: Win_GParted::activate_copy()
Move vector of partition objects to a Win_GParted class member (#750168) Win_GParted::Refresh_Visual() used a local variable containing a copy of the vector of partitions in the current device to be displayed. After visually applying pending operations it loaded copies of each partition object into the GUI widgets to display the disk graphic and partition list, DrawingAreaVisualDisk and TreeView_Details classes respectively. When a partition is selected in the UI, again a partition object is copied. Also several of the partition dialogs, including the information dialog, take a copy of the partition object. All these are copies of the same set of partition objects, those currently being displayed in the UI. Move the vector of displayed partitions from a local variable in Refresh_Visual() to a Win_GParted member variable. This will allow for the above cases to be changed to used pointers and references to the same set of partition objects. The valid lifetime of pointers to elements in this partition object vector is from one refresh to the next, when the vector is cleared and repopulated with a new set of partition objects. This is exactly what is needed as the GUI widgets are reloaded on each refresh, the selected partition is reset and none of the partition dialog objects exist. Dialog objects being created and destroyed on each use. On the other hand some copies of partition objects currently being displayed, still need to be made because they have lifetimes which need to last longer than the next call to Refresh_Visual(). Specifically the source of the copy partition and the partition objects copied into the in the list of pending operations. Bug 750168 - Reduce the amount of copying of partition objects
2015-05-15 08:51:26 -06:00
display_partitions = devices[current_device].partitions;
2004-09-19 14:24:53 -06:00
//make all operations visible
for ( unsigned int t = 0 ; t < operations .size(); t++ )
if ( operations[ t ] ->device == devices[ current_device ] )
Move vector of partition objects to a Win_GParted class member (#750168) Win_GParted::Refresh_Visual() used a local variable containing a copy of the vector of partitions in the current device to be displayed. After visually applying pending operations it loaded copies of each partition object into the GUI widgets to display the disk graphic and partition list, DrawingAreaVisualDisk and TreeView_Details classes respectively. When a partition is selected in the UI, again a partition object is copied. Also several of the partition dialogs, including the information dialog, take a copy of the partition object. All these are copies of the same set of partition objects, those currently being displayed in the UI. Move the vector of displayed partitions from a local variable in Refresh_Visual() to a Win_GParted member variable. This will allow for the above cases to be changed to used pointers and references to the same set of partition objects. The valid lifetime of pointers to elements in this partition object vector is from one refresh to the next, when the vector is cleared and repopulated with a new set of partition objects. This is exactly what is needed as the GUI widgets are reloaded on each refresh, the selected partition is reset and none of the partition dialog objects exist. Dialog objects being created and destroyed on each use. On the other hand some copies of partition objects currently being displayed, still need to be made because they have lifetimes which need to last longer than the next call to Refresh_Visual(). Specifically the source of the copy partition and the partition objects copied into the in the list of pending operations. Bug 750168 - Reduce the amount of copying of partition objects
2015-05-15 08:51:26 -06:00
operations[t]->apply_to_visual( display_partitions );
hbox_operations .load_operations( operations ) ;
2004-09-19 14:24:53 -06:00
//set new statusbartext
statusbar .pop() ;
statusbar .push( String::ucompose( ngettext( "%1 operation pending"
, "%1 operations pending"
, operations .size()
)
, operations .size()
)
);
if ( ! operations .size() )
allow_undo_clear_apply( false ) ;
// Refresh copy partition source as necessary and select the largest unallocated
// partition if there is one.
selected_partition_ptr = NULL;
Sector largest_unalloc_size = -1 ;
Sector current_size ;
Move vector of partition objects to a Win_GParted class member (#750168) Win_GParted::Refresh_Visual() used a local variable containing a copy of the vector of partitions in the current device to be displayed. After visually applying pending operations it loaded copies of each partition object into the GUI widgets to display the disk graphic and partition list, DrawingAreaVisualDisk and TreeView_Details classes respectively. When a partition is selected in the UI, again a partition object is copied. Also several of the partition dialogs, including the information dialog, take a copy of the partition object. All these are copies of the same set of partition objects, those currently being displayed in the UI. Move the vector of displayed partitions from a local variable in Refresh_Visual() to a Win_GParted member variable. This will allow for the above cases to be changed to used pointers and references to the same set of partition objects. The valid lifetime of pointers to elements in this partition object vector is from one refresh to the next, when the vector is cleared and repopulated with a new set of partition objects. This is exactly what is needed as the GUI widgets are reloaded on each refresh, the selected partition is reset and none of the partition dialog objects exist. Dialog objects being created and destroyed on each use. On the other hand some copies of partition objects currently being displayed, still need to be made because they have lifetimes which need to last longer than the next call to Refresh_Visual(). Specifically the source of the copy partition and the partition objects copied into the in the list of pending operations. Bug 750168 - Reduce the amount of copying of partition objects
2015-05-15 08:51:26 -06:00
for ( unsigned int t = 0 ; t < display_partitions.size() ; t++ )
2004-09-19 14:24:53 -06:00
{
if ( copied_partition != NULL && display_partitions[t].get_path() == copied_partition->get_path() )
{
delete copied_partition;
copied_partition = display_partitions[t].clone();
}
Move vector of partition objects to a Win_GParted class member (#750168) Win_GParted::Refresh_Visual() used a local variable containing a copy of the vector of partitions in the current device to be displayed. After visually applying pending operations it loaded copies of each partition object into the GUI widgets to display the disk graphic and partition list, DrawingAreaVisualDisk and TreeView_Details classes respectively. When a partition is selected in the UI, again a partition object is copied. Also several of the partition dialogs, including the information dialog, take a copy of the partition object. All these are copies of the same set of partition objects, those currently being displayed in the UI. Move the vector of displayed partitions from a local variable in Refresh_Visual() to a Win_GParted member variable. This will allow for the above cases to be changed to used pointers and references to the same set of partition objects. The valid lifetime of pointers to elements in this partition object vector is from one refresh to the next, when the vector is cleared and repopulated with a new set of partition objects. This is exactly what is needed as the GUI widgets are reloaded on each refresh, the selected partition is reset and none of the partition dialog objects exist. Dialog objects being created and destroyed on each use. On the other hand some copies of partition objects currently being displayed, still need to be made because they have lifetimes which need to last longer than the next call to Refresh_Visual(). Specifically the source of the copy partition and the partition objects copied into the in the list of pending operations. Bug 750168 - Reduce the amount of copying of partition objects
2015-05-15 08:51:26 -06:00
switch ( display_partitions[t].type )
2004-09-19 14:24:53 -06:00
{
case TYPE_EXTENDED:
Move vector of partition objects to a Win_GParted class member (#750168) Win_GParted::Refresh_Visual() used a local variable containing a copy of the vector of partitions in the current device to be displayed. After visually applying pending operations it loaded copies of each partition object into the GUI widgets to display the disk graphic and partition list, DrawingAreaVisualDisk and TreeView_Details classes respectively. When a partition is selected in the UI, again a partition object is copied. Also several of the partition dialogs, including the information dialog, take a copy of the partition object. All these are copies of the same set of partition objects, those currently being displayed in the UI. Move the vector of displayed partitions from a local variable in Refresh_Visual() to a Win_GParted member variable. This will allow for the above cases to be changed to used pointers and references to the same set of partition objects. The valid lifetime of pointers to elements in this partition object vector is from one refresh to the next, when the vector is cleared and repopulated with a new set of partition objects. This is exactly what is needed as the GUI widgets are reloaded on each refresh, the selected partition is reset and none of the partition dialog objects exist. Dialog objects being created and destroyed on each use. On the other hand some copies of partition objects currently being displayed, still need to be made because they have lifetimes which need to last longer than the next call to Refresh_Visual(). Specifically the source of the copy partition and the partition objects copied into the in the list of pending operations. Bug 750168 - Reduce the amount of copying of partition objects
2015-05-15 08:51:26 -06:00
for ( unsigned int u = 0 ; u < display_partitions[t].logicals.size() ; u ++ )
{
if ( copied_partition != NULL &&
display_partitions[t].logicals[u].get_path() == copied_partition->get_path() )
{
delete copied_partition;
copied_partition = display_partitions[t].logicals[u].clone();
}
Refresh copy source when its a logical partition too (#754827) Perform a copy, reformat source and paste sequence in GParted. When the source is a primary partition everything works as expected, with the newly pasted partition reflecting the reformatted source. However when the source is a logical partition GParted thinks it is pasting the original source, rather than the reformatted source. The same is also true for other file system manipulation operations: resize, file system label and new UUID. It is just that reformatting the source to a different file system type is the most obvious in the UI and causes the most significantly wrong actions to be performed. For example start with an ext4 logical partition, select it for copy, format it to xfs and paste into a new partition. GParted thinks the second operation will create a copy of an ext4 file system instead of the xfs file system. When applied the operation details are: Format /dev/sdd5 as xfs + calibrate /dev/sdd5 + clear old file system signatures in /dev/sdd5 + set partition type on /dev/sdd5 + create new xfs file system + mkfs.xfs -f -L "" /dev/sdd5 Copy /dev/sdd5 to /dev/sdd (start at 131.00 MiB) + calibrate /dev/sdd5 + check file system on /dev/sdd5 for errors and (if possible) fix them + e2fsck -f -y -v -C 0 /dev/sdd5 e2fsck: Subperblock invalid, trying backup blocks... Resize inode not valid. Recreate? yes ... /dev/sdd5: ***** FILE SYSTEM WAS MODIFIED ***** + create empty partition + set partition type on /dev/sdd6 new partition type: ext4 + copy file system of /dev/sdd5 to /dev/sdd6 using internal algorithm ... GParted formatted sdd5 to xfs, but then the copy step ran e2fsck and managed to resurrect the ext4 file system and then performed a block copy of it to partition sdd6. The copy step should have ran xfs_repair and used xfsdump | xfsrestore to copy the xfs file system. Afterwards sdd5 contains both xfs and ext4 signatures. # wipefs /dev/sdd5 offset type ---------------------------------------------------------------- 0x438 ext4 [filesystem] UUID: f0ed4247-76db-4d93-b3bc-c7da4a70f95e 0x0 xfs [filesystem] UUID: 1ac8e7c3-0311-4c64-8e4a-b715a23ea0bd This has been broken at least as far back as GParted 0.1.0. Fix by simply refreshing the copy source partition object when it is a logical partition too, as well as when it is a primary partition. Bug 754827 - Copy, reformat source and paste a logical partition thinks it's pasting the original file system
2015-09-10 06:49:28 -06:00
Move vector of partition objects to a Win_GParted class member (#750168) Win_GParted::Refresh_Visual() used a local variable containing a copy of the vector of partitions in the current device to be displayed. After visually applying pending operations it loaded copies of each partition object into the GUI widgets to display the disk graphic and partition list, DrawingAreaVisualDisk and TreeView_Details classes respectively. When a partition is selected in the UI, again a partition object is copied. Also several of the partition dialogs, including the information dialog, take a copy of the partition object. All these are copies of the same set of partition objects, those currently being displayed in the UI. Move the vector of displayed partitions from a local variable in Refresh_Visual() to a Win_GParted member variable. This will allow for the above cases to be changed to used pointers and references to the same set of partition objects. The valid lifetime of pointers to elements in this partition object vector is from one refresh to the next, when the vector is cleared and repopulated with a new set of partition objects. This is exactly what is needed as the GUI widgets are reloaded on each refresh, the selected partition is reset and none of the partition dialog objects exist. Dialog objects being created and destroyed on each use. On the other hand some copies of partition objects currently being displayed, still need to be made because they have lifetimes which need to last longer than the next call to Refresh_Visual(). Specifically the source of the copy partition and the partition objects copied into the in the list of pending operations. Bug 750168 - Reduce the amount of copying of partition objects
2015-05-15 08:51:26 -06:00
switch ( display_partitions[t].logicals[u].type )
{
case TYPE_UNALLOCATED:
Move vector of partition objects to a Win_GParted class member (#750168) Win_GParted::Refresh_Visual() used a local variable containing a copy of the vector of partitions in the current device to be displayed. After visually applying pending operations it loaded copies of each partition object into the GUI widgets to display the disk graphic and partition list, DrawingAreaVisualDisk and TreeView_Details classes respectively. When a partition is selected in the UI, again a partition object is copied. Also several of the partition dialogs, including the information dialog, take a copy of the partition object. All these are copies of the same set of partition objects, those currently being displayed in the UI. Move the vector of displayed partitions from a local variable in Refresh_Visual() to a Win_GParted member variable. This will allow for the above cases to be changed to used pointers and references to the same set of partition objects. The valid lifetime of pointers to elements in this partition object vector is from one refresh to the next, when the vector is cleared and repopulated with a new set of partition objects. This is exactly what is needed as the GUI widgets are reloaded on each refresh, the selected partition is reset and none of the partition dialog objects exist. Dialog objects being created and destroyed on each use. On the other hand some copies of partition objects currently being displayed, still need to be made because they have lifetimes which need to last longer than the next call to Refresh_Visual(). Specifically the source of the copy partition and the partition objects copied into the in the list of pending operations. Bug 750168 - Reduce the amount of copying of partition objects
2015-05-15 08:51:26 -06:00
current_size = display_partitions[t].logicals[u].get_sector_length();
if ( current_size > largest_unalloc_size )
{
largest_unalloc_size = current_size ;
selected_partition_ptr = & display_partitions[t].logicals[u];
}
break;
default:
break;
}
}
break;
case TYPE_UNALLOCATED:
Move vector of partition objects to a Win_GParted class member (#750168) Win_GParted::Refresh_Visual() used a local variable containing a copy of the vector of partitions in the current device to be displayed. After visually applying pending operations it loaded copies of each partition object into the GUI widgets to display the disk graphic and partition list, DrawingAreaVisualDisk and TreeView_Details classes respectively. When a partition is selected in the UI, again a partition object is copied. Also several of the partition dialogs, including the information dialog, take a copy of the partition object. All these are copies of the same set of partition objects, those currently being displayed in the UI. Move the vector of displayed partitions from a local variable in Refresh_Visual() to a Win_GParted member variable. This will allow for the above cases to be changed to used pointers and references to the same set of partition objects. The valid lifetime of pointers to elements in this partition object vector is from one refresh to the next, when the vector is cleared and repopulated with a new set of partition objects. This is exactly what is needed as the GUI widgets are reloaded on each refresh, the selected partition is reset and none of the partition dialog objects exist. Dialog objects being created and destroyed on each use. On the other hand some copies of partition objects currently being displayed, still need to be made because they have lifetimes which need to last longer than the next call to Refresh_Visual(). Specifically the source of the copy partition and the partition objects copied into the in the list of pending operations. Bug 750168 - Reduce the amount of copying of partition objects
2015-05-15 08:51:26 -06:00
current_size = display_partitions[t].get_sector_length();
if ( current_size > largest_unalloc_size )
{
largest_unalloc_size = current_size ;
selected_partition_ptr = & display_partitions[t];
}
break;
default :
break;
2004-09-19 14:24:53 -06:00
}
}
Move vector of partition objects to a Win_GParted class member (#750168) Win_GParted::Refresh_Visual() used a local variable containing a copy of the vector of partitions in the current device to be displayed. After visually applying pending operations it loaded copies of each partition object into the GUI widgets to display the disk graphic and partition list, DrawingAreaVisualDisk and TreeView_Details classes respectively. When a partition is selected in the UI, again a partition object is copied. Also several of the partition dialogs, including the information dialog, take a copy of the partition object. All these are copies of the same set of partition objects, those currently being displayed in the UI. Move the vector of displayed partitions from a local variable in Refresh_Visual() to a Win_GParted member variable. This will allow for the above cases to be changed to used pointers and references to the same set of partition objects. The valid lifetime of pointers to elements in this partition object vector is from one refresh to the next, when the vector is cleared and repopulated with a new set of partition objects. This is exactly what is needed as the GUI widgets are reloaded on each refresh, the selected partition is reset and none of the partition dialog objects exist. Dialog objects being created and destroyed on each use. On the other hand some copies of partition objects currently being displayed, still need to be made because they have lifetimes which need to last longer than the next call to Refresh_Visual(). Specifically the source of the copy partition and the partition objects copied into the in the list of pending operations. Bug 750168 - Reduce the amount of copying of partition objects
2015-05-15 08:51:26 -06:00
// frame visualdisk
drawingarea_visualdisk.load_partitions( display_partitions, devices[current_device].length );
// treeview details
treeview_detail.load_partitions( display_partitions );
set_valid_operations() ;
// Process Gtk events to redraw visuals with reloaded partition details
while ( Gtk::Main::events_pending() )
Gtk::Main::iteration();
if ( largest_unalloc_size >= 0 )
{
// Flashing redraw work around. Inform visuals of selection of the
// largest unallocated partition after drawing those visuals above.
drawingarea_visualdisk.set_selected( selected_partition_ptr );
treeview_detail.set_selected( selected_partition_ptr );
// Process Gtk events to draw selection
while ( Gtk::Main::events_pending() )
Gtk::Main::iteration();
}
2004-09-19 14:24:53 -06:00
}
// Confirms that the pointer points to one of the partition objects in the vector of
// displayed partitions, Win_GParted::display_partitions[].
// Usage: g_assert( valid_display_partition_ptr( my_partition_ptr ) );
bool Win_GParted::valid_display_partition_ptr( const Partition * partition_ptr )
{
for ( unsigned int i = 0 ; i < display_partitions.size() ; i++ )
{
if ( & display_partitions[i] == partition_ptr )
return true;
else if ( display_partitions[i].type == TYPE_EXTENDED )
{
for ( unsigned int j = 0 ; j < display_partitions[i].logicals.size() ; j++ )
{
if ( & display_partitions[i].logicals[j] == partition_ptr )
return true;
}
}
}
return false;
}
bool Win_GParted::Quit_Check_Operations()
2004-09-19 14:24:53 -06:00
{
if ( operations .size() )
2004-09-19 14:24:53 -06:00
{
Gtk::MessageDialog dialog( *this,
_("Quit GParted?"),
false,
Gtk::MESSAGE_QUESTION,
Gtk::BUTTONS_NONE,
true );
dialog .set_secondary_text( String::ucompose( ngettext( "%1 operation is currently pending."
, "%1 operations are currently pending."
, operations .size()
)
, operations .size()
)
) ;
2004-09-19 14:24:53 -06:00
dialog .add_button( Gtk::Stock::QUIT, Gtk::RESPONSE_CLOSE );
dialog .add_button( Gtk::Stock::CANCEL,Gtk::RESPONSE_CANCEL );
if ( dialog .run() == Gtk::RESPONSE_CANCEL )
return false;//don't close GParted
2004-09-19 14:24:53 -06:00
}
return true; //close GParted
}
void Win_GParted::set_valid_operations()
2004-09-19 14:24:53 -06:00
{
allow_new( false ); allow_delete( false ); allow_resize( false ); allow_copy( false );
allow_paste( false ); allow_format( false ); allow_toggle_busy_state( false ) ;
allow_name_partition( false ); allow_manage_flags( false ); allow_check( false );
allow_label_filesystem( false ); allow_change_uuid( false ); allow_info( false );
dynamic_cast<Gtk::Label*>( menu_partition .items()[ MENU_TOGGLE_BUSY ] .get_child() )
->set_label( FileSystem::get_generic_text ( CTEXT_DEACTIVATE_FILESYSTEM ) ) ;
menu_partition .items()[ MENU_TOGGLE_BUSY ] .show() ;
menu_partition .items()[ MENU_MOUNT ] .hide() ;
// No partition selected ...
if ( ! selected_partition_ptr )
return ;
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
// Get filesystem capabilities
fs = gparted_core.get_fs( selected_partition_ptr->filesystem );
//if there's something, there's some info ;)
allow_info( true ) ;
// Set an appropriate name for the activate/deactivate menu item.
const FileSystem * filesystem_object = gparted_core.get_filesystem_object( selected_partition_ptr->filesystem );
if ( filesystem_object )
dynamic_cast<Gtk::Label*>( menu_partition .items()[ MENU_TOGGLE_BUSY ] .get_child() )
->set_label( filesystem_object->get_custom_text( selected_partition_ptr->busy
? CTEXT_DEACTIVATE_FILESYSTEM
: CTEXT_ACTIVATE_FILESYSTEM ) );
else
dynamic_cast<Gtk::Label*>( menu_partition .items()[ MENU_TOGGLE_BUSY ] .get_child() )
->set_label( FileSystem::get_generic_text ( selected_partition_ptr->busy
? CTEXT_DEACTIVATE_FILESYSTEM
: CTEXT_ACTIVATE_FILESYSTEM )
) ;
// Only permit mount/unmount, swapon/swapoff, activate/deactivate if action is available
if ( selected_partition_ptr->status == STAT_REAL
&& selected_partition_ptr->type != TYPE_EXTENDED
&& selected_partition_ptr->filesystem != FS_LVM2_PV
&& selected_partition_ptr->filesystem != FS_LINUX_SWRAID
&& selected_partition_ptr->filesystem != FS_LUKS
&& ( selected_partition_ptr->busy
|| selected_partition_ptr->get_mountpoints().size() /* Have mount point(s) */
|| selected_partition_ptr->filesystem == FS_LINUX_SWAP
)
)
allow_toggle_busy_state( true ) ;
//Only permit VG deactivation if busy, or activation if not busy and a member of a VG.
// For now specifically allow activation of an exported VG, which LVM will fail
// with "Volume group "VGNAME" is exported", otherwise user won't know why the
// inactive PV can't be activated.
if ( selected_partition_ptr->status == STAT_REAL
&& selected_partition_ptr->type != TYPE_EXTENDED
&& selected_partition_ptr->filesystem == FS_LVM2_PV
&& ( selected_partition_ptr->busy
|| ( ! selected_partition_ptr->busy
&& ! selected_partition_ptr->get_mountpoints().empty() // VGNAME from mount point
)
)
)
allow_toggle_busy_state( true ) ;
// Allow naming on devices that support it
if ( selected_partition_ptr->type != TYPE_UNALLOCATED &&
selected_partition_ptr->status == STAT_REAL &&
devices[current_device].partition_naming_supported() )
allow_name_partition( true );
// Manage flags
if ( selected_partition_ptr->type != TYPE_UNALLOCATED &&
selected_partition_ptr->status == STAT_REAL &&
! selected_partition_ptr->whole_device )
allow_manage_flags( true );
#ifdef ENABLE_ONLINE_RESIZE
// Find out if online resizing is possible
if ( selected_partition_ptr->busy )
{
if ( ( fs .online_grow || fs .online_shrink ) && ! devices[ current_device ] .readonly )
allow_resize( true ) ;
}
#endif
// Only unmount/swapoff/VG deactivate or online actions allowed if busy
if ( selected_partition_ptr->busy )
return ;
// UNALLOCATED
if ( selected_partition_ptr->type == TYPE_UNALLOCATED )
2004-09-19 14:24:53 -06:00
{
allow_new( true );
// Find out if there is a partition to be copied and if it fits inside this unallocated space
if ( copied_partition != NULL && ! devices[current_device].readonly )
{
Byte_Value required_size ;
if ( copied_partition->filesystem == FS_XFS )
required_size = copied_partition->estimated_min_size() * copied_partition->sector_size;
else
required_size = copied_partition->get_byte_length();
//Determine if space is needed for the Master Boot Record or
// the Extended Boot Record. Generally an an additional track or MEBIBYTE
// is required so for our purposes reserve a MEBIBYTE in front of the partition.
// NOTE: This logic also contained in Dialog_Base_Partition::MB_Needed_for_Boot_Record
if ( ( selected_partition_ptr->inside_extended
&& selected_partition_ptr->type == TYPE_UNALLOCATED
)
|| ( selected_partition_ptr->type == TYPE_LOGICAL )
/* Beginning of disk device */
|| ( selected_partition_ptr->sector_start <= (MEBIBYTE / selected_partition_ptr->sector_size) )
)
required_size += MEBIBYTE;
//Determine if space is needed for the Extended Boot Record for a logical partition
// after this partition. Generally an an additional track or MEBIBYTE
// is required so for our purposes reserve a MEBIBYTE in front of the partition.
if ( ( ( selected_partition_ptr->inside_extended
&& selected_partition_ptr->type == TYPE_UNALLOCATED
)
|| ( selected_partition_ptr->type == TYPE_LOGICAL )
)
&& ( selected_partition_ptr->sector_end
< ( devices[ current_device ] .length
- ( 2 * MEBIBYTE / devices[ current_device ] .sector_size )
)
)
)
required_size += MEBIBYTE;
//Determine if space is needed for the backup partition on a GPT partition table
if ( ( devices[ current_device ] .disktype == "gpt" )
&& ( ( devices[current_device].length - selected_partition_ptr->sector_end )
< ( MEBIBYTE / devices[ current_device ] .sector_size )
)
)
required_size += MEBIBYTE ;
if ( required_size <= selected_partition_ptr->get_byte_length() )
allow_paste( true ) ;
}
2004-09-19 14:24:53 -06:00
return ;
}
// EXTENDED
if ( selected_partition_ptr->type == TYPE_EXTENDED )
{
// Deletion is only allowed when there are no logical partitions inside.
if ( selected_partition_ptr->logicals.size() == 1 &&
selected_partition_ptr->logicals.back().type == TYPE_UNALLOCATED )
allow_delete( true ) ;
if ( ! devices[ current_device ] .readonly )
allow_resize( true ) ;
return ;
}
// PRIMARY and LOGICAL
if ( selected_partition_ptr->type == TYPE_PRIMARY || selected_partition_ptr->type == TYPE_LOGICAL )
2004-09-19 14:24:53 -06:00
{
allow_format( true ) ;
Enable operations on whole disk device virtual partitions (#743181) Enable operations on whole disk devices containing any recognised file system. The new partition operation on an empty whole disk device continues to display the "No partition table found on device /dev/DEVICE" information dialog. Specifically unsupported operations: * Delete - Deletion of a partition only involves removal of the entry in the partition table leaving the file system intact on the disk. However this doesn't work for a whole disk device file system. Instead the file system signatures would have to be erased which is much more destructive and virtually impossible to undo. Therefore don't implement whole disk device file system deletion. Alternatives are to format the file system to cleared or create a partition table on the device. Both of these imply overwriting the existing data and set the expectation that undo is not possible. * Manage flags - There's no partition table, so there's no partition, so there's no flags. Resize/Move operation is being supported so that a whole disk device file system can be resized to handle devices which can be resize, such as those from SANs or Linux Software RAID arrays. The start of the file system must remain fixed so move won't be allowed. So far only simple operations work if they don't need libparted support at all [1], or only need libparted support for the calibrate step AND the file system on the whole disk device is recognised by libparted [2]. (Needs libparted to provide a "loop" partition, hence the recognition requirement, so that the calibrate step can successfully read the virtual "loop" partition table. Doesn't matter whether it's an old version of libparted and it gets the name of the device wrong as GParted is already using the whole disk device name anyway). [1] Operations not needing any libparted support: Mount on, Unmount, Swapon, Swapoff, Activate and Deactivate [2] Operations only needing libparted support for the calibrate step: Check, Label, New UUID Bug 743181 - Add unpartitioned drive read-write support
2014-12-31 05:41:03 -07:00
// only allow deletion of partitions within a partition table
if ( ! selected_partition_ptr->whole_device )
Enable operations on whole disk device virtual partitions (#743181) Enable operations on whole disk devices containing any recognised file system. The new partition operation on an empty whole disk device continues to display the "No partition table found on device /dev/DEVICE" information dialog. Specifically unsupported operations: * Delete - Deletion of a partition only involves removal of the entry in the partition table leaving the file system intact on the disk. However this doesn't work for a whole disk device file system. Instead the file system signatures would have to be erased which is much more destructive and virtually impossible to undo. Therefore don't implement whole disk device file system deletion. Alternatives are to format the file system to cleared or create a partition table on the device. Both of these imply overwriting the existing data and set the expectation that undo is not possible. * Manage flags - There's no partition table, so there's no partition, so there's no flags. Resize/Move operation is being supported so that a whole disk device file system can be resized to handle devices which can be resize, such as those from SANs or Linux Software RAID arrays. The start of the file system must remain fixed so move won't be allowed. So far only simple operations work if they don't need libparted support at all [1], or only need libparted support for the calibrate step AND the file system on the whole disk device is recognised by libparted [2]. (Needs libparted to provide a "loop" partition, hence the recognition requirement, so that the calibrate step can successfully read the virtual "loop" partition table. Doesn't matter whether it's an old version of libparted and it gets the name of the device wrong as GParted is already using the whole disk device name anyway). [1] Operations not needing any libparted support: Mount on, Unmount, Swapon, Swapoff, Activate and Deactivate [2] Operations only needing libparted support for the calibrate step: Check, Label, New UUID Bug 743181 - Add unpartitioned drive read-write support
2014-12-31 05:41:03 -07:00
allow_delete( true );
//find out if resizing/moving is possible
if ( (fs .grow || fs .shrink || fs .move ) && ! devices[ current_device ] .readonly )
2004-09-19 14:24:53 -06:00
allow_resize( true ) ;
//only allow copying of real partitions
if ( selected_partition_ptr->status == STAT_REAL && fs.copy )
allow_copy( true ) ;
//only allow labelling of real partitions that support labelling
if ( selected_partition_ptr->status == STAT_REAL && fs.write_label )
allow_label_filesystem( true );
//only allow changing UUID of real partitions that support it
if ( selected_partition_ptr->status == STAT_REAL && fs.write_uuid )
allow_change_uuid( true ) ;
// Generate Mount on submenu, except for LVM2 PVs borrowing mount point to
// display the VGNAME and read-only supported LUKS.
if ( selected_partition_ptr->filesystem != FS_LVM2_PV &&
selected_partition_ptr->filesystem != FS_LUKS &&
selected_partition_ptr->get_mountpoints().size() )
{
menu = menu_partition .items()[ MENU_MOUNT ] .get_submenu() ;
menu ->items() .clear() ;
for ( unsigned int t = 0 ; t < selected_partition_ptr->get_mountpoints().size() ; t++ )
{
menu ->items() .push_back(
Gtk::Menu_Helpers::MenuElem(
selected_partition_ptr->get_mountpoints()[t],
sigc::bind<unsigned int>( sigc::mem_fun(*this, &Win_GParted::activate_mount_partition), t ) ) );
dynamic_cast<Gtk::Label*>( menu ->items() .back() .get_child() ) ->set_use_underline( false ) ;
}
menu_partition .items()[ MENU_TOGGLE_BUSY ] .hide() ;
menu_partition .items()[ MENU_MOUNT ] .show() ;
}
// See if there is a partition to be copied and it fits inside this selected partition
if ( copied_partition != NULL &&
copied_partition->get_byte_length() <= selected_partition_ptr->get_byte_length() &&
selected_partition_ptr->status == STAT_REAL &&
*copied_partition != *selected_partition_ptr )
allow_paste( true );
//see if we can somehow check/repair this file system....
if ( fs.check && selected_partition_ptr->status == STAT_REAL )
allow_check( true ) ;
2004-09-19 14:24:53 -06:00
}
}
Only allow Undo and Apply after merging operations (#699452) It was possible to make GParted crash by adding a label, check or new UUID operation and then applying the operation before the view of pending operations had finished fully opening. The operation would be successfully applied but GParted would crash afterwards. The fault was that Add_Operation() still enabled the Undo and Apply buttons and processed the GTK event loop before merging the list of pending operations. Faulty code flow went like this: activate_*() Add_Operation() Add operation to the operations[] vector Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Merge operations in the operations[] vector << Core dump here >> Merge_Operations() Refresh_Visual() This faulty code flow came about when merging of operations was added and it didn't appreciate that the operations[] vector could have been processed and cleared by Add_Operations() before the merge step. Relevant commit: b10349ae37df06b7bf7de91ea93a3913535ade3a Merge overlapping operations (#438573) Fragment of code in the label operation case: 2454 void Win_GParted::activate_label_partition() 2455 { ... 2472 Add_Operation( operation ) ; 2473 2474 // Verify if the two operations can be merged 2475 for ( unsigned int t = 0 ; t < operations .size() - 1 ; t++ ) 2476 { 2477 if ( operations[ t ] ->type == OPERATION_LABEL_PARTITION ) 2478 { 2479 if ( Merge_Operations( t, operations .size() - 1 ) ) 2480 break; 2481 } 2482 } Commentary in the crashing label operation case: 2472 The pending operation was already applied when Add_Operation() returned resulting in the operations[] vector being cleared setting its size to 0. 2475 The return type of operations.size() is an unsigned integral, so the upper limit of the for loop is t < 0UL - 1. Assuming a 32-bit machine that's t < 4294967295. 2477 operations[] vector is access from out of bounds offset 0 upwards until unallocated memory is accessed resulting in a core dump. Fix this by not enabling the Undo and Apply buttons and processing the GTK event loop until after merging of operations has been performed. Fixed code flow goes like this: activate_*() Add_Operation() Add operation to the operations[] vector Merge operations in the operations[] vector Merge_Operations() show_operationslist() Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Not allowing the operations list to be process until after the merge step is the be correct ordering. This also prevents the new operation from flashing up in the operations list and then immediately disappearing if merged. In the case of adding the first operation, delaying enabling the Undo and Apply buttons is enough as the buttons were previously disabled preventing the operation being applied before the merge. In the case of adding further operations, processing of the GTK event loop must also be delayed until after the merge to prevent the operations being applied before the merge. Although that window of opportunity would only be microseconds. Bug #699452 - Crash when applying operations before pending operations fully displayed
2013-05-17 10:01:42 -06:00
void Win_GParted::show_operationslist()
{
//Enable (or disable) Undo and Apply buttons
allow_undo_clear_apply( operations .size() ) ;
//Updates view of operations list and sensitivity of Undo and Apply buttons
Refresh_Visual();
if ( operations .size() == 1 ) //first operation, open operationslist
open_operationslist() ;
//FIXME: A slight flicker may be introduced by this extra display refresh.
//An extra display refresh seems to prevent the disk area visual disk from
// disappearing when enough operations are added to require a scrollbar
// (about 4 operations with default window size).
// Note that commenting out the code to
// "//make scrollwindow focus on the last operation in the list"
// in HBoxOperations::load_operations() prevents this problem from occurring as well.
// See also Win_GParted::activate_undo().
drawingarea_visualdisk .queue_draw() ;
}
void Win_GParted::open_operationslist()
{
if ( ! OPERATIONSLIST_OPEN )
{
OPERATIONSLIST_OPEN = true ;
hbox_operations .show() ;
for ( int t = vpaned_main .get_height() ; t > ( vpaned_main .get_height() - 100 ) ; t -= 5 )
{
vpaned_main .set_position( t );
while ( Gtk::Main::events_pending() )
Gtk::Main::iteration() ;
}
static_cast<Gtk::CheckMenuItem *>( & menubar_main .items()[ 2 ] .get_submenu() ->items()[ 1 ] )
->set_active( true ) ;
}
}
void Win_GParted::close_operationslist()
2004-09-19 14:24:53 -06:00
{
if ( OPERATIONSLIST_OPEN )
2004-09-19 14:24:53 -06:00
{
OPERATIONSLIST_OPEN = false ;
for ( int t = vpaned_main .get_position() ; t < vpaned_main .get_height() ; t += 5 )
{
vpaned_main .set_position( t ) ;
while ( Gtk::Main::events_pending() )
Gtk::Main::iteration();
}
hbox_operations .hide() ;
static_cast<Gtk::CheckMenuItem *>( & menubar_main .items()[ 2 ] .get_submenu() ->items()[ 1 ] )
->set_active( false ) ;
2004-09-19 14:24:53 -06:00
}
}
void Win_GParted::clear_operationslist()
2004-09-19 14:24:53 -06:00
{
remove_operation( -1, true ) ;
close_operationslist() ;
Refresh_Visual() ;
2004-09-19 14:24:53 -06:00
}
void Win_GParted::combo_devices_changed()
{
unsigned int old_current_device = current_device;
2004-09-19 14:24:53 -06:00
//set new current device
current_device = combo_devices .get_active_row_number() ;
if ( current_device == (unsigned int) -1 )
current_device = old_current_device;
if ( current_device >= devices .size() )
current_device = 0 ;
set_title( String::ucompose( _("%1 - GParted"), devices[ current_device ] .get_path() ) );
2004-09-19 14:24:53 -06:00
//refresh label_device_info
Fill_Label_Device_Info();
2004-09-19 14:24:53 -06:00
//rebuild visualdisk and treeview
Refresh_Visual();
//uodate radiobuttons..
if ( menubar_main .items()[ 0 ] .get_submenu() ->items()[ 1 ] .get_submenu() )
static_cast<Gtk::RadioMenuItem *>(
& menubar_main .items()[ 0 ] .get_submenu() ->items()[ 1 ] .get_submenu() ->
items()[ current_device ] ) ->set_active( true ) ;
}
void Win_GParted::radio_devices_changed( unsigned int item )
{
if ( static_cast<Gtk::RadioMenuItem *>(
& menubar_main .items()[ 0 ] .get_submenu() ->items()[ 1 ] .get_submenu() ->
items()[ item ] ) ->get_active() )
{
combo_devices .set_active( item ) ;
}
2004-09-19 14:24:53 -06:00
}
void Win_GParted::on_show()
{
Gtk::Window::on_show() ;
vpaned_main .set_position( vpaned_main .get_height() ) ;
close_operationslist() ;
Make GParted exit when closed before the initial load completes (#771816) If the GParted main window is closed before the initial device load completed gpartedbin never exits. The main window closes but the process sits there idle forever. Subsequently running GParted reports this error: # gparted The process gpartedbin is already running. Only one gpartedbin process is permitted. If the user is running GParted from a desktop menu they will never see this error so they will never know why GParted won't start any more. More technically, it is if the main window is closed before the Win_GParted::on_show() callback completes. I assume the Gtk main loop doesn't setup the normal quit handling until the on_show() callback finishes drawing the main window for the first time. Following this hint [1], move the initial device load from the on_show() callback to immediately after it completes by using a run once idle callback setup in on_show(). This looks exactly the same to the user except now gpartedbin exits when the main window is closed during the initial device load. Note that GParted finished the device load before exiting. This is exactly the same as happens when exiting during subsequent device refreshes. [1] How to know when a Gtk Window is fully shown? http://stackoverflow.com/questions/14663212/how-to-know-when-a-gtk-window-is-fully-shown "If you want to know when your main window appears the first time, it is far easier (and saner) add a g_idle_add after your show_all call." Bug 771816 - GParted never exits if the main window is closed before the initial device load completes
2016-09-21 06:49:02 -06:00
// Register callback for as soon as the main window has been shown to perform the
// first load of the disk device details. Do it this way because the Gtk main
Make GParted exit when closed before the initial load completes (#771816) If the GParted main window is closed before the initial device load completed gpartedbin never exits. The main window closes but the process sits there idle forever. Subsequently running GParted reports this error: # gparted The process gpartedbin is already running. Only one gpartedbin process is permitted. If the user is running GParted from a desktop menu they will never see this error so they will never know why GParted won't start any more. More technically, it is if the main window is closed before the Win_GParted::on_show() callback completes. I assume the Gtk main loop doesn't setup the normal quit handling until the on_show() callback finishes drawing the main window for the first time. Following this hint [1], move the initial device load from the on_show() callback to immediately after it completes by using a run once idle callback setup in on_show(). This looks exactly the same to the user except now gpartedbin exits when the main window is closed during the initial device load. Note that GParted finished the device load before exiting. This is exactly the same as happens when exiting during subsequent device refreshes. [1] How to know when a Gtk Window is fully shown? http://stackoverflow.com/questions/14663212/how-to-know-when-a-gtk-window-is-fully-shown "If you want to know when your main window appears the first time, it is far easier (and saner) add a g_idle_add after your show_all call." Bug 771816 - GParted never exits if the main window is closed before the initial device load completes
2016-09-21 06:49:02 -06:00
// loop doesn't seem to enable quit handling until on_show(), this function, has
// drawn the main window for the first time and returned, and we want Close Window
// [Alt-F4] to work during the initial load of the disk device details.
Make GParted exit when closed before the initial load completes (#771816) If the GParted main window is closed before the initial device load completed gpartedbin never exits. The main window closes but the process sits there idle forever. Subsequently running GParted reports this error: # gparted The process gpartedbin is already running. Only one gpartedbin process is permitted. If the user is running GParted from a desktop menu they will never see this error so they will never know why GParted won't start any more. More technically, it is if the main window is closed before the Win_GParted::on_show() callback completes. I assume the Gtk main loop doesn't setup the normal quit handling until the on_show() callback finishes drawing the main window for the first time. Following this hint [1], move the initial device load from the on_show() callback to immediately after it completes by using a run once idle callback setup in on_show(). This looks exactly the same to the user except now gpartedbin exits when the main window is closed during the initial device load. Note that GParted finished the device load before exiting. This is exactly the same as happens when exiting during subsequent device refreshes. [1] How to know when a Gtk Window is fully shown? http://stackoverflow.com/questions/14663212/how-to-know-when-a-gtk-window-is-fully-shown "If you want to know when your main window appears the first time, it is far easier (and saner) add a g_idle_add after your show_all call." Bug 771816 - GParted never exits if the main window is closed before the initial device load completes
2016-09-21 06:49:02 -06:00
g_idle_add( initial_device_refresh, this );
}
Make GParted exit when closed before the initial load completes (#771816) If the GParted main window is closed before the initial device load completed gpartedbin never exits. The main window closes but the process sits there idle forever. Subsequently running GParted reports this error: # gparted The process gpartedbin is already running. Only one gpartedbin process is permitted. If the user is running GParted from a desktop menu they will never see this error so they will never know why GParted won't start any more. More technically, it is if the main window is closed before the Win_GParted::on_show() callback completes. I assume the Gtk main loop doesn't setup the normal quit handling until the on_show() callback finishes drawing the main window for the first time. Following this hint [1], move the initial device load from the on_show() callback to immediately after it completes by using a run once idle callback setup in on_show(). This looks exactly the same to the user except now gpartedbin exits when the main window is closed during the initial device load. Note that GParted finished the device load before exiting. This is exactly the same as happens when exiting during subsequent device refreshes. [1] How to know when a Gtk Window is fully shown? http://stackoverflow.com/questions/14663212/how-to-know-when-a-gtk-window-is-fully-shown "If you want to know when your main window appears the first time, it is far easier (and saner) add a g_idle_add after your show_all call." Bug 771816 - GParted never exits if the main window is closed before the initial device load completes
2016-09-21 06:49:02 -06:00
// Callback used to load the disk device details for the first time
gboolean Win_GParted::initial_device_refresh( gpointer data )
{
Win_GParted *win_gparted = static_cast<Win_GParted *>( data );
win_gparted->menu_gparted_refresh_devices();
return false; // one shot g_idle_add() callback
}
void Win_GParted::menu_gparted_refresh_devices()
2004-09-19 14:24:53 -06:00
{
show_pulsebar( _("Scanning all devices...") ) ;
gparted_core.set_devices( devices );
hide_pulsebar();
//check if current_device is still available (think about hotpluggable stuff like usbdevices)
if ( current_device >= devices .size() )
current_device = 0 ;
//see if there are any pending operations on non-existent devices
//NOTE that this isn't 100% foolproof since some stuff (e.g. sourcedevice of copy) may slip through.
//but anyone who removes the sourcedevice before applying the operations gets what he/she deserves :-)
//FIXME: this actually sucks ;) see if we can use STL predicates here..
unsigned int i ;
for ( unsigned int t = 0 ; t < operations .size() ; t++ )
{
for ( i = 0 ; i < devices .size() && devices[ i ] != operations[ t ] ->device ; i++ ) {}
if ( i >= devices .size() )
remove_operation( t-- ) ;
}
//if no devices were detected we disable some stuff and show a message in the statusbar
if ( devices .empty() )
{
this ->set_title( _("GParted") );
combo_devices .hide() ;
menubar_main .items()[ 0 ] .get_submenu() ->items()[ 1 ] .set_sensitive( false ) ;
menubar_main .items()[ 1 ] .set_sensitive( false ) ;
menubar_main .items()[ 2 ] .set_sensitive( false ) ;
menubar_main .items()[ 3 ] .set_sensitive( false ) ;
menubar_main .items()[ 4 ] .set_sensitive( false ) ;
toolbar_main .set_sensitive( false ) ;
drawingarea_visualdisk .set_sensitive( false ) ;
treeview_detail .set_sensitive( false ) ;
Fill_Label_Device_Info( true ) ;
drawingarea_visualdisk .clear() ;
treeview_detail .clear() ;
//hmzz, this is really paranoid, but i think it's the right thing to do ;)
hbox_operations .clear() ;
close_operationslist() ;
remove_operation( -1, true ) ;
statusbar .pop() ;
statusbar .push( _( "No devices detected" ) );
}
else //at least one device detected
{
combo_devices .show() ;
menubar_main .items()[ 0 ] .get_submenu() ->items()[ 1 ] .set_sensitive( true ) ;
menubar_main .items()[ 1 ] .set_sensitive( true ) ;
menubar_main .items()[ 2 ] .set_sensitive( true ) ;
menubar_main .items()[ 3 ] .set_sensitive( true ) ;
menubar_main .items()[ 4 ] .set_sensitive( true ) ;
toolbar_main .set_sensitive( true ) ;
drawingarea_visualdisk .set_sensitive( true ) ;
treeview_detail .set_sensitive( true ) ;
refresh_combo_devices() ;
}
2004-09-19 14:24:53 -06:00
}
void Win_GParted::menu_gparted_features()
{
DialogFeatures dialog ;
dialog .set_transient_for( *this ) ;
dialog .load_filesystems( gparted_core .get_filesystems() ) ;
while ( dialog .run() == Gtk::RESPONSE_OK )
{
// Button [Rescan For Supported Actions] pressed in the dialog. Rescan
// for available core and file system specific commands and update the
// view accordingly in the dialog.
GParted_Core::find_supported_core();
gparted_core .find_supported_filesystems() ;
dialog .load_filesystems( gparted_core .get_filesystems() ) ;
//recreate format menu...
menu_partition .items()[ MENU_FORMAT ] .remove_submenu() ;
menu_partition .items()[ MENU_FORMAT ] .set_submenu( * create_format_menu() ) ;
menu_partition .items()[ MENU_FORMAT ] .get_submenu() ->show_all_children() ;
}
}
void Win_GParted::menu_gparted_quit()
2004-09-19 14:24:53 -06:00
{
if ( Quit_Check_Operations() )
this ->hide();
2004-09-19 14:24:53 -06:00
}
void Win_GParted::menu_view_harddisk_info()
{
if ( static_cast<Gtk::CheckMenuItem *>( & menubar_main .items()[ 2 ] .get_submenu() ->items()[ 0 ] ) ->get_active() )
{ //open harddisk information
hpaned_main .get_child1() ->show() ;
for ( int t = hpaned_main .get_position() ; t < 250 ; t += 15 )
2004-09-27 14:12:47 -06:00
{
hpaned_main .set_position( t );
while ( Gtk::Main::events_pending() )
Gtk::Main::iteration();
2004-09-27 14:12:47 -06:00
}
}
else
2004-09-27 14:12:47 -06:00
{ //close harddisk information
for ( int t = hpaned_main .get_position() ; t > 0 ; t -= 15 )
2004-09-27 14:12:47 -06:00
{
hpaned_main .set_position( t );
while ( Gtk::Main::events_pending() )
Gtk::Main::iteration();
2004-09-27 14:12:47 -06:00
}
hpaned_main .get_child1() ->hide() ;
2004-09-27 14:12:47 -06:00
}
}
void Win_GParted::menu_view_operations()
{
if ( static_cast<Gtk::CheckMenuItem *>( & menubar_main .items()[ 2 ] .get_submenu() ->items()[ 1 ] ) ->get_active() )
open_operationslist() ;
else
close_operationslist() ;
}
void Win_GParted::show_disklabel_unrecognized ( Glib::ustring device_name )
{
//Display dialog box indicating that no partition table was found on the device
Gtk::MessageDialog dialog( *this,
/*TO TRANSLATORS: looks like No partition table found on device /dev/sda */
String::ucompose( _( "No partition table found on device %1" ), device_name ),
false,
Gtk::MESSAGE_INFO,
Gtk::BUTTONS_OK,
true ) ;
Glib::ustring tmp_msg = _( "A partition table is required before partitions can be added." ) ;
tmp_msg += "\n" ;
tmp_msg += _( "To create a new partition table choose the menu item:" ) ;
tmp_msg += "\n" ;
/*TO TRANSLATORS: this message represents the menu item Create Partition Table under the Device menu. */
tmp_msg += _( "Device --> Create Partition Table." ) ;
dialog .set_secondary_text( tmp_msg ) ;
dialog .run() ;
}
void Win_GParted::show_help_dialog( const Glib::ustring & filename /* E.g., gparted */
, const Glib::ustring & link_id /* For context sensitive help */
)
2004-09-19 14:24:53 -06:00
{
GError *error = NULL ;
GdkScreen *gscreen = NULL ;
Glib::ustring uri = "ghelp:" + filename ;
if (link_id .size() > 0 ) {
uri = uri + "?" + link_id ;
}
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 )
{
//Try opening yelp application directly
g_clear_error( &error ) ; //Clear error from trying to open gparted help manual above (gtk_show_uri or gnome-open).
Glib::ustring command = "yelp " + uri ;
gdk_spawn_command_line_on_screen( gscreen, command .c_str(), &error ) ;
}
if ( error != NULL )
{
Gtk::MessageDialog dialog( *this
, _( "Unable to open GParted Manual help file" )
, false
, Gtk::MESSAGE_ERROR
, Gtk::BUTTONS_OK
, true
) ;
dialog .set_secondary_text( error ->message ) ;
dialog .run() ;
}
2004-09-19 14:24:53 -06:00
}
void Win_GParted::menu_help_contents()
{
#ifdef ENABLE_HELP_DOC
//GParted was built with help documentation
show_help_dialog( "gparted", "" );
#else
//GParted was built *without* help documentation using --disable-doc
Gtk::MessageDialog dialog( *this,
_( "Documentation is not available" ),
false,
Gtk::MESSAGE_INFO,
Gtk::BUTTONS_OK,
true ) ;
Glib::ustring tmp_msg = _( "This build of gparted is configured without documentation." ) ;
tmp_msg += "\n" ;
tmp_msg += _( "Documentation is available at the project web site." ) ;
tmp_msg += "\n" ;
tmp_msg += "http://gparted.org" ;
dialog .set_secondary_text( tmp_msg ) ;
dialog .run() ;
#endif
}
2004-09-19 14:24:53 -06:00
void Win_GParted::menu_help_about()
2004-09-19 14:24:53 -06:00
{
std::vector<Glib::ustring> strings ;
Gtk::AboutDialog dialog ;
2004-09-19 14:24:53 -06:00
dialog .set_transient_for( *this ) ;
dialog .set_name( _("GParted") ) ;
dialog .set_logo_icon_name( "gparted" ) ;
dialog .set_version( VERSION ) ;
dialog .set_comments( _( "GNOME Partition Editor" ) ) ;
2015-02-01 13:14:05 -07:00
std::string names ;
names = "Copyright © 2004-2006 Bart Hakvoort" ;
2016-01-18 09:28:01 -07:00
names += "\nCopyright © 2008-2016 Curtis Gedak" ;
names += "\nCopyright © 2011-2016 Mike Fleetwood" ;
2015-02-01 13:14:05 -07:00
dialog .set_copyright( names ) ;
//authors
//Names listed in alphabetical order by LAST name.
//See also AUTHORS file -- names listed in opposite order to try to be fair.
strings .push_back( "Sinlu Bes <e80f00@gmail.com>" ) ;
strings .push_back( "Luca Bruno <lucab@debian.org>" ) ;
strings .push_back( "Wrolf Courtney <wrolf@wrolf.net>" ) ;
strings .push_back( "Jérôme Dumesnil <jerome.dumesnil@gmail.com>" ) ;
strings .push_back( "Markus Elfring <elfring@users.sourceforge.net>" ) ;
strings .push_back( "Mike Fleetwood <mike.fleetwood@googlemail.com>" ) ;
strings .push_back( "Curtis Gedak <gedakc@users.sf.net>" ) ;
strings .push_back( "Matthias Gehre <m.gehre@gmx.de>" ) ;
strings .push_back( "Rogier Goossens <goossens.rogier@gmail.com>" ) ;
strings .push_back( "Bart Hakvoort <gparted@users.sf.net>" ) ;
strings .push_back( "Seth Heeren <sgheeren@gmail.com>" ) ;
strings .push_back( "Joan Lledó <joanlluislledo@gmail.com>" ) ;
strings .push_back( "Phillip Susi <psusi@cfl.rr.com>" ) ;
strings. push_back( "Michael Zimmermann <sigmaepsilon92@gmail.com>" ) ;
dialog .set_authors( strings ) ;
strings .clear() ;
//artists
strings .push_back( "Sebastian Kraft <kraft.sebastian@gmail.com>" ) ;
dialog .set_artists( strings ) ;
strings .clear() ;
/*TO TRANSLATORS: your name(s) here please, if there are more translators put newlines (\n) between the names.
It's a good idea to provide the url of your translation team as well. Thanks! */
Glib::ustring str_credits = _("translator-credits") ;
if ( str_credits != "translator-credits" )
dialog .set_translator_credits( str_credits ) ;
//the url is not clickable - should not invoke web browser as root
dialog .set_website_label( "http://gparted.org" ) ;
dialog .run() ;
2004-09-19 14:24:53 -06:00
}
void Win_GParted::on_partition_selected( const Partition * partition_ptr, bool src_is_treeview )
2004-09-19 14:24:53 -06:00
{
selected_partition_ptr = partition_ptr;
set_valid_operations() ;
if ( src_is_treeview )
drawingarea_visualdisk.set_selected( partition_ptr );
else
treeview_detail.set_selected( partition_ptr );
}
void Win_GParted::on_partition_activated()
{
activate_info() ;
}
void Win_GParted::on_partition_popup_menu( unsigned int button, unsigned int time )
{
menu_partition .popup( button, time );
2004-09-19 14:24:53 -06:00
}
bool Win_GParted::max_amount_prim_reached()
{
int primary_count = 0;
for ( unsigned int i = 0 ; i < display_partitions.size() ; i ++ )
{
if ( display_partitions[i].type == TYPE_PRIMARY || display_partitions[i].type == TYPE_EXTENDED )
primary_count ++;
}
//Display error if user tries to create more primary partitions than the partition table can hold.
if ( ! selected_partition_ptr->inside_extended && primary_count >= devices[current_device].max_prims )
{
Gtk::MessageDialog dialog(
*this,
String::ucompose( ngettext( "It is not possible to create more than %1 primary partition"
, "It is not possible to create more than %1 primary partitions"
, devices[ current_device ] .max_prims
)
, devices[ current_device ] .max_prims
),
false,
Gtk::MESSAGE_ERROR,
Gtk::BUTTONS_OK,
true ) ;
dialog .set_secondary_text(
_( "If you want more partitions you should first create an extended partition. Such a partition can contain other partitions. Because an extended partition is also a primary partition it might be necessary to remove a primary partition first.") ) ;
dialog .run() ;
return true ;
}
return false ;
}
2004-09-19 14:24:53 -06:00
void Win_GParted::activate_resize()
2004-09-19 14:24:53 -06:00
{
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
PartitionVector * display_partitions_ptr = &display_partitions;
if ( selected_partition_ptr->type == TYPE_LOGICAL )
{
unsigned int ext = 0 ;
while ( ext < display_partitions.size() && display_partitions[ext].type != TYPE_EXTENDED )
ext++;
Adjust pointers to prevent crash when resizing a logical partition (#752587) Opening the Resize/Move dialog on a logical partition causes GParted to crash. This crash affects current GParted GIT HEAD, but does not affect GParted 0.22.0. Git bisect identifies that it was broken with the following commit: Remove Set_Data() from the copy, resize/move and new dialog class APIs 7a4a375ed629fea77995c98d13bd1992231be6fb The problem was trying to treat the reference display_partitions_ref like a pointer, and in particular on line 1732 trying to make it refer to the a different vector of partitions, .logicals sub-vector. 1721 void Win_GParted::activate_resize() 1722 { ... 1726 std::vector<Partition> & display_partitions_ref = display_partitions; 1727 if ( selected_partition_ptr->type == TYPE_LOGICAL ) 1728 { 1729 unsigned int ext = 0 ; 1730 while ( ext < display_partitions.size() && display_partitions[ext].type != TYPE_EXTENDED ) 1731 ext++; * 1732 display_partitions_ref = display_partitions[ext].logicals; 1733 } 1734 1735 Dialog_Partition_Resize_Move dialog( gparted_core.get_fs( selected_partition_ptr->filesystem ), 1736 *selected_partition_ptr, 1737 display_partitions_ref ); What was actually happening was that the .logicals sub-vector was being copied, replacing the display_partitions vector and freeing the original sub-vector. This left selected_partition_ptr pointing to the original memory where the selected partition use to exist in the .logicals sub-vector. At some point in the Dialog_Partition_Resize_Move class *selected_partition_ptr was referenced, accessing the freed memory. Crash soon followed. Fix by using a pointer instead of a reference, which can be assigned to point to a different object. Bug 752587 - GParted crashing when opening Resize/Move dialog on logical partition
2015-07-20 12:59:46 -06:00
display_partitions_ptr = &display_partitions[ext].logicals;
}
Dialog_Partition_Resize_Move dialog( gparted_core.get_fs( selected_partition_ptr->filesystem ),
*selected_partition_ptr,
Adjust pointers to prevent crash when resizing a logical partition (#752587) Opening the Resize/Move dialog on a logical partition causes GParted to crash. This crash affects current GParted GIT HEAD, but does not affect GParted 0.22.0. Git bisect identifies that it was broken with the following commit: Remove Set_Data() from the copy, resize/move and new dialog class APIs 7a4a375ed629fea77995c98d13bd1992231be6fb The problem was trying to treat the reference display_partitions_ref like a pointer, and in particular on line 1732 trying to make it refer to the a different vector of partitions, .logicals sub-vector. 1721 void Win_GParted::activate_resize() 1722 { ... 1726 std::vector<Partition> & display_partitions_ref = display_partitions; 1727 if ( selected_partition_ptr->type == TYPE_LOGICAL ) 1728 { 1729 unsigned int ext = 0 ; 1730 while ( ext < display_partitions.size() && display_partitions[ext].type != TYPE_EXTENDED ) 1731 ext++; * 1732 display_partitions_ref = display_partitions[ext].logicals; 1733 } 1734 1735 Dialog_Partition_Resize_Move dialog( gparted_core.get_fs( selected_partition_ptr->filesystem ), 1736 *selected_partition_ptr, 1737 display_partitions_ref ); What was actually happening was that the .logicals sub-vector was being copied, replacing the display_partitions vector and freeing the original sub-vector. This left selected_partition_ptr pointing to the original memory where the selected partition use to exist in the .logicals sub-vector. At some point in the Dialog_Partition_Resize_Move class *selected_partition_ptr was referenced, accessing the freed memory. Crash soon followed. Fix by using a pointer instead of a reference, which can be assigned to point to a different object. Bug 752587 - GParted crashing when opening Resize/Move dialog on logical partition
2015-07-20 12:59:46 -06:00
*display_partitions_ptr );
dialog .set_transient_for( *this ) ;
if ( dialog .run() == Gtk::RESPONSE_OK )
2004-09-19 14:24:53 -06:00
{
dialog .hide() ;
Partition * part_temp = dialog.Get_New_Partition().clone();
// When resizing/moving a partition which already exists on the disk all
// possible operations could be pending so only try merging with the
// previous operation.
MergeType mergetype = MERGE_LAST_WITH_PREV;
// If selected partition is NEW we simply remove the NEW operation from the list and add
// it again with the new size and position ( unless it's an EXTENDED )
if ( selected_partition_ptr->status == STAT_NEW && selected_partition_ptr->type != TYPE_EXTENDED )
2004-09-19 14:24:53 -06:00
{
part_temp->status = STAT_NEW;
// On a partition which is pending creation only resize/move and
// format operations are possible. These operations are always
// mergeable with the pending operation which will create the
// partition. Hence merge with any earlier operations to achieve
// this.
mergetype = MERGE_LAST_WITH_ANY;
2004-09-19 14:24:53 -06:00
}
Operation * operation = new OperationResizeMove( devices[current_device],
*selected_partition_ptr,
*part_temp );
operation->icon = render_icon( Gtk::Stock::GOTO_LAST, Gtk::ICON_SIZE_MENU );
delete part_temp;
part_temp = NULL;
// Display warning if moving a non-extended partition which already exists
// on the disk.
if ( operation->get_partition_original().status != STAT_NEW &&
operation->get_partition_original().sector_start != operation->get_partition_new().sector_start &&
operation->get_partition_original().type != TYPE_EXTENDED )
{
// Warn that move operation might break boot process
Gtk::MessageDialog dialog( *this,
_("Moving a partition might cause your operating system to fail to boot"),
false,
Gtk::MESSAGE_WARNING,
Gtk::BUTTONS_OK,
true );
Glib::ustring tmp_msg =
/*TO TRANSLATORS: looks like You queued an operation to move the start sector of partition /dev/sda3. */
String::ucompose( _( "You have queued an operation to move the start sector of partition %1." )
, operation->get_partition_original().get_path() );
tmp_msg += _(" Failure to boot is most likely to occur if you move the GNU/Linux partition containing /boot, or if you move the Windows system partition C:.");
tmp_msg += "\n";
tmp_msg += _("You can learn how to repair the boot configuration in the GParted FAQ.");
tmp_msg += "\n";
tmp_msg += "http://gparted.org/faq.php";
tmp_msg += "\n\n";
tmp_msg += _("Moving a partition might take a very long time to apply.");
dialog.set_secondary_text( tmp_msg );
dialog.run();
}
Add_Operation( operation );
merge_operations( mergetype );
2004-09-19 14:24:53 -06:00
}
Only allow Undo and Apply after merging operations (#699452) It was possible to make GParted crash by adding a label, check or new UUID operation and then applying the operation before the view of pending operations had finished fully opening. The operation would be successfully applied but GParted would crash afterwards. The fault was that Add_Operation() still enabled the Undo and Apply buttons and processed the GTK event loop before merging the list of pending operations. Faulty code flow went like this: activate_*() Add_Operation() Add operation to the operations[] vector Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Merge operations in the operations[] vector << Core dump here >> Merge_Operations() Refresh_Visual() This faulty code flow came about when merging of operations was added and it didn't appreciate that the operations[] vector could have been processed and cleared by Add_Operations() before the merge step. Relevant commit: b10349ae37df06b7bf7de91ea93a3913535ade3a Merge overlapping operations (#438573) Fragment of code in the label operation case: 2454 void Win_GParted::activate_label_partition() 2455 { ... 2472 Add_Operation( operation ) ; 2473 2474 // Verify if the two operations can be merged 2475 for ( unsigned int t = 0 ; t < operations .size() - 1 ; t++ ) 2476 { 2477 if ( operations[ t ] ->type == OPERATION_LABEL_PARTITION ) 2478 { 2479 if ( Merge_Operations( t, operations .size() - 1 ) ) 2480 break; 2481 } 2482 } Commentary in the crashing label operation case: 2472 The pending operation was already applied when Add_Operation() returned resulting in the operations[] vector being cleared setting its size to 0. 2475 The return type of operations.size() is an unsigned integral, so the upper limit of the for loop is t < 0UL - 1. Assuming a 32-bit machine that's t < 4294967295. 2477 operations[] vector is access from out of bounds offset 0 upwards until unallocated memory is accessed resulting in a core dump. Fix this by not enabling the Undo and Apply buttons and processing the GTK event loop until after merging of operations has been performed. Fixed code flow goes like this: activate_*() Add_Operation() Add operation to the operations[] vector Merge operations in the operations[] vector Merge_Operations() show_operationslist() Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Not allowing the operations list to be process until after the merge step is the be correct ordering. This also prevents the new operation from flashing up in the operations list and then immediately disappearing if merged. In the case of adding the first operation, delaying enabling the Undo and Apply buttons is enough as the buttons were previously disabled preventing the operation being applied before the merge. In the case of adding further operations, processing of the GTK event loop must also be delayed until after the merge to prevent the operations being applied before the merge. Although that window of opportunity would only be microseconds. Bug #699452 - Crash when applying operations before pending operations fully displayed
2013-05-17 10:01:42 -06:00
show_operationslist() ;
2004-09-19 14:24:53 -06:00
}
void Win_GParted::activate_copy()
2004-09-19 14:24:53 -06:00
{
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
delete copied_partition;
copied_partition = selected_partition_ptr->clone();
2004-09-19 14:24:53 -06:00
}
void Win_GParted::activate_paste()
2004-09-19 14:24:53 -06:00
{
g_assert( copied_partition != NULL ); // Bug: Paste called without partition to copy
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
// Unrecognised whole disk device (See GParted_Core::get_devices_threads(), "unrecognized")
if ( selected_partition_ptr->whole_device && selected_partition_ptr->type == TYPE_UNALLOCATED )
2004-09-19 14:24:53 -06:00
{
show_disklabel_unrecognized( devices [current_device ] .get_path() ) ;
return ;
}
if ( selected_partition_ptr->type == TYPE_UNALLOCATED )
{
if ( ! max_amount_prim_reached() )
{
// We don't want the messages, mount points or name of the source
// partition for the new partition being created.
Partition * part_temp = copied_partition->clone();
Display messages for encrypted file systems (#760080) At the moment any messages for an encrypted file system aren't shown, only messages from the outer PartitionLUKS object are shown. Also in Win_GParted::activate_paste() the selected Partition object, possibly a derived PartitionLUKS, is cloned and the messages cleared. Therefore a set of accessor methods must be provided to query and modify partition messages. Messages will be stored in the Partition object to which they are added and retrieved from all. So in the case of a derived PartitionLUKS they will be retrieved from the messages vector of the PartitionLUKS object itself and the messages vector for the encrypted file system it contains. To replace code like this in GParted_Core: partition_temp->messages = messages; We might naturally provide a set_messages() method which assigns the messages vector and is used like this: partition_temp->set_messages( messages ); However on a PartitionLUKS object what should set_messages() do? By the name it will replace any existing messages in the PartitionLUKS object itself, but what should happen to the messages for the contained encrypted Partition object? Should they be cleared or left alone? Rather than implement set_messages() with unclear semantics implement append_messages(), which in the PartitionLUKS object case will clearly leave any messages for the contained encrypted Partition object alone. Append_messages() is then used to add messages as the Partition or PartitionLUKS objects when populating the data in GParted_Core. Bug 760080 - Implement read-only LUKS support
2015-12-31 09:32:08 -07:00
part_temp->clear_messages();
part_temp->clear_mountpoints();
part_temp->name.clear();
Dialog_Partition_Copy dialog( gparted_core.get_fs( copied_partition->filesystem ),
*selected_partition_ptr,
*part_temp );
delete part_temp;
part_temp = NULL;
dialog .set_transient_for( *this );
if ( dialog .run() == Gtk::RESPONSE_OK )
{
dialog .hide() ;
Operation * operation = new OperationCopy( devices[current_device],
*selected_partition_ptr,
dialog.Get_New_Partition(),
*copied_partition );
operation ->icon = render_icon( Gtk::Stock::COPY, Gtk::ICON_SIZE_MENU );
Stop overriding real path when pasting into existing partitions (#766349) When composing a copy operation it always named the destination partition as "copy of /dev/SRC". For the case of pasting into unallocated space creating a new partition this was the right thing to do as the partition doesn't yet exist so the path is not yet known. However for the case of pasting into an existing partition the path is known and replacing it with "copy of /dev/SRC" is wrong. No other operation when operating on an existing partition changes it path. Given a set of existing partitions, sdb1 to sdb4, compose a set of copy operations as: copy sdb1 to sdb2, copy sdb2 to sdb3 and copy sdb3 to sdb4. The displayed partitions before being applied become: /dev/sdb1 copy of /dev/sdb1 copy of copy of /dev/sdb1 copy of copy of copy of /dev/sdb1 And the pending operations are named: Copy /dev/sdb1 to /dev/sdb2 Copy copy of /dev/sdb1 to /dev/sdb3 Copy copy of copy of /dev/sdb1 to /sev/sdb4 This is perverse. In the case of pasting into an existing partition keep the real path name. This keeps the partitions being displayed as: /dev/sdb1 /dev/sdb2 /dev/sdb3 /dev/sdb4 And the pending operations named as: Copy /dev/sdb1 to /dev/sdb2 Copy /dev/sdb2 to /dev/sdb3 Copy /dev/sdb3 to /dev/sdb4 Much more understandable. Also switch to an upper case "C" in "Copy of /dev/SRC" as the temporary path name when pasting into unallocated space. Finally update the comment in calibrate_partition() to describe the remaining cases when re-adding the path is still required. Bug 766349 - Resolve code ugliness with partition path getting set to "copy of /dev/SRC"
2016-05-10 09:11:36 -06:00
// When pasting into unallocated space set a temporary
// path of "Copy of /dev/SRC" for display purposes until
// the partition is created and the real path queried.
OperationCopy * copy_op = static_cast<OperationCopy*>( operation );
copy_op->get_partition_new().set_path(
Stop overriding real path when pasting into existing partitions (#766349) When composing a copy operation it always named the destination partition as "copy of /dev/SRC". For the case of pasting into unallocated space creating a new partition this was the right thing to do as the partition doesn't yet exist so the path is not yet known. However for the case of pasting into an existing partition the path is known and replacing it with "copy of /dev/SRC" is wrong. No other operation when operating on an existing partition changes it path. Given a set of existing partitions, sdb1 to sdb4, compose a set of copy operations as: copy sdb1 to sdb2, copy sdb2 to sdb3 and copy sdb3 to sdb4. The displayed partitions before being applied become: /dev/sdb1 copy of /dev/sdb1 copy of copy of /dev/sdb1 copy of copy of copy of /dev/sdb1 And the pending operations are named: Copy /dev/sdb1 to /dev/sdb2 Copy copy of /dev/sdb1 to /dev/sdb3 Copy copy of copy of /dev/sdb1 to /sev/sdb4 This is perverse. In the case of pasting into an existing partition keep the real path name. This keeps the partitions being displayed as: /dev/sdb1 /dev/sdb2 /dev/sdb3 /dev/sdb4 And the pending operations named as: Copy /dev/sdb1 to /dev/sdb2 Copy /dev/sdb2 to /dev/sdb3 Copy /dev/sdb3 to /dev/sdb4 Much more understandable. Also switch to an upper case "C" in "Copy of /dev/SRC" as the temporary path name when pasting into unallocated space. Finally update the comment in calibrate_partition() to describe the remaining cases when re-adding the path is still required. Bug 766349 - Resolve code ugliness with partition path getting set to "copy of /dev/SRC"
2016-05-10 09:11:36 -06:00
String::ucompose( _("Copy of %1"),
copy_op->get_partition_copied().get_path() ) );
Stop overriding real path when pasting into existing partitions (#766349) When composing a copy operation it always named the destination partition as "copy of /dev/SRC". For the case of pasting into unallocated space creating a new partition this was the right thing to do as the partition doesn't yet exist so the path is not yet known. However for the case of pasting into an existing partition the path is known and replacing it with "copy of /dev/SRC" is wrong. No other operation when operating on an existing partition changes it path. Given a set of existing partitions, sdb1 to sdb4, compose a set of copy operations as: copy sdb1 to sdb2, copy sdb2 to sdb3 and copy sdb3 to sdb4. The displayed partitions before being applied become: /dev/sdb1 copy of /dev/sdb1 copy of copy of /dev/sdb1 copy of copy of copy of /dev/sdb1 And the pending operations are named: Copy /dev/sdb1 to /dev/sdb2 Copy copy of /dev/sdb1 to /dev/sdb3 Copy copy of copy of /dev/sdb1 to /sev/sdb4 This is perverse. In the case of pasting into an existing partition keep the real path name. This keeps the partitions being displayed as: /dev/sdb1 /dev/sdb2 /dev/sdb3 /dev/sdb4 And the pending operations named as: Copy /dev/sdb1 to /dev/sdb2 Copy /dev/sdb2 to /dev/sdb3 Copy /dev/sdb3 to /dev/sdb4 Much more understandable. Also switch to an upper case "C" in "Copy of /dev/SRC" as the temporary path name when pasting into unallocated space. Finally update the comment in calibrate_partition() to describe the remaining cases when re-adding the path is still required. Bug 766349 - Resolve code ugliness with partition path getting set to "copy of /dev/SRC"
2016-05-10 09:11:36 -06:00
Add_Operation( operation ) ;
}
}
2004-09-19 14:24:53 -06:00
}
else
{
bool shown_dialog = false ;
// VGNAME from mount mount
if ( selected_partition_ptr->filesystem == FS_LVM2_PV &&
! selected_partition_ptr->get_mountpoint().empty() )
{
if ( ! remove_non_empty_lvm2_pv_dialog( OPERATION_COPY ) )
return ;
shown_dialog = true ;
}
Partition * partition_new = selected_partition_ptr->clone();
partition_new->alignment = ALIGN_STRICT;
partition_new->filesystem = copied_partition->filesystem;
partition_new->set_filesystem_label( copied_partition->get_filesystem_label() );
partition_new->uuid = copied_partition->uuid;
Sector new_size = partition_new->get_sector_length();
if ( copied_partition->get_sector_length() == new_size )
{
// Pasting into same size existing partition, therefore only block
// copy operation will be performed maintaining the file system
// size.
partition_new->set_sector_usage(
copied_partition->sectors_used + copied_partition->sectors_unused,
copied_partition->sectors_unused );
}
else
{
// Pasting into larger existing partition, therefore block copy
// followed by file system grow operations (if supported) will be
// performed making the file system fill the partition.
partition_new->set_sector_usage(
new_size,
new_size - copied_partition->sectors_used );
}
Display messages for encrypted file systems (#760080) At the moment any messages for an encrypted file system aren't shown, only messages from the outer PartitionLUKS object are shown. Also in Win_GParted::activate_paste() the selected Partition object, possibly a derived PartitionLUKS, is cloned and the messages cleared. Therefore a set of accessor methods must be provided to query and modify partition messages. Messages will be stored in the Partition object to which they are added and retrieved from all. So in the case of a derived PartitionLUKS they will be retrieved from the messages vector of the PartitionLUKS object itself and the messages vector for the encrypted file system it contains. To replace code like this in GParted_Core: partition_temp->messages = messages; We might naturally provide a set_messages() method which assigns the messages vector and is used like this: partition_temp->set_messages( messages ); However on a PartitionLUKS object what should set_messages() do? By the name it will replace any existing messages in the PartitionLUKS object itself, but what should happen to the messages for the contained encrypted Partition object? Should they be cleared or left alone? Rather than implement set_messages() with unclear semantics implement append_messages(), which in the PartitionLUKS object case will clearly leave any messages for the contained encrypted Partition object alone. Append_messages() is then used to add messages as the Partition or PartitionLUKS objects when populating the data in GParted_Core. Bug 760080 - Implement read-only LUKS support
2015-12-31 09:32:08 -07:00
partition_new->clear_messages();
Operation * operation = new OperationCopy( devices[current_device],
*selected_partition_ptr,
*partition_new,
*copied_partition );
operation ->icon = render_icon( Gtk::Stock::COPY, Gtk::ICON_SIZE_MENU );
delete partition_new;
partition_new = NULL;
Add_Operation( operation ) ;
if ( ! shown_dialog )
{
//Only warn that this paste operation will overwrite data in the existing
// partition if not already shown the remove non-empty LVM2 PV dialog.
Gtk::MessageDialog dialog( *this
, _( "You have pasted into an existing partition" )
, false
, Gtk::MESSAGE_WARNING
, Gtk::BUTTONS_OK
, true
) ;
/*TO TRANSLATORS: looks like The data in /dev/sda3 will be lost if you apply this operation. */
dialog .set_secondary_text(
String::ucompose( _( "The data in %1 will be lost if you apply this operation." ),
selected_partition_ptr->get_path() ) );
dialog .run() ;
}
}
Only allow Undo and Apply after merging operations (#699452) It was possible to make GParted crash by adding a label, check or new UUID operation and then applying the operation before the view of pending operations had finished fully opening. The operation would be successfully applied but GParted would crash afterwards. The fault was that Add_Operation() still enabled the Undo and Apply buttons and processed the GTK event loop before merging the list of pending operations. Faulty code flow went like this: activate_*() Add_Operation() Add operation to the operations[] vector Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Merge operations in the operations[] vector << Core dump here >> Merge_Operations() Refresh_Visual() This faulty code flow came about when merging of operations was added and it didn't appreciate that the operations[] vector could have been processed and cleared by Add_Operations() before the merge step. Relevant commit: b10349ae37df06b7bf7de91ea93a3913535ade3a Merge overlapping operations (#438573) Fragment of code in the label operation case: 2454 void Win_GParted::activate_label_partition() 2455 { ... 2472 Add_Operation( operation ) ; 2473 2474 // Verify if the two operations can be merged 2475 for ( unsigned int t = 0 ; t < operations .size() - 1 ; t++ ) 2476 { 2477 if ( operations[ t ] ->type == OPERATION_LABEL_PARTITION ) 2478 { 2479 if ( Merge_Operations( t, operations .size() - 1 ) ) 2480 break; 2481 } 2482 } Commentary in the crashing label operation case: 2472 The pending operation was already applied when Add_Operation() returned resulting in the operations[] vector being cleared setting its size to 0. 2475 The return type of operations.size() is an unsigned integral, so the upper limit of the for loop is t < 0UL - 1. Assuming a 32-bit machine that's t < 4294967295. 2477 operations[] vector is access from out of bounds offset 0 upwards until unallocated memory is accessed resulting in a core dump. Fix this by not enabling the Undo and Apply buttons and processing the GTK event loop until after merging of operations has been performed. Fixed code flow goes like this: activate_*() Add_Operation() Add operation to the operations[] vector Merge operations in the operations[] vector Merge_Operations() show_operationslist() Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Not allowing the operations list to be process until after the merge step is the be correct ordering. This also prevents the new operation from flashing up in the operations list and then immediately disappearing if merged. In the case of adding the first operation, delaying enabling the Undo and Apply buttons is enough as the buttons were previously disabled preventing the operation being applied before the merge. In the case of adding further operations, processing of the GTK event loop must also be delayed until after the merge to prevent the operations being applied before the merge. Although that window of opportunity would only be microseconds. Bug #699452 - Crash when applying operations before pending operations fully displayed
2013-05-17 10:01:42 -06:00
show_operationslist() ;
2004-09-19 14:24:53 -06:00
}
void Win_GParted::activate_new()
2004-09-19 14:24:53 -06:00
{
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
// Unrecognised whole disk device (See GParted_Core::get_devices_threads(), "unrecognized")
if ( selected_partition_ptr->whole_device && selected_partition_ptr->type == TYPE_UNALLOCATED )
{
show_disklabel_unrecognized( devices [current_device ] .get_path() ) ;
}
else if ( ! max_amount_prim_reached() )
{
// Check if an extended partition already exist; so that the dialog can
// decide whether to allow the creation of the only extended partition
// type or not.
bool any_extended = false;
for ( unsigned int i = 0 ; i < display_partitions.size() ; i ++ )
{
if ( display_partitions[i].type == TYPE_EXTENDED )
{
any_extended = true;
break;
}
}
Dialog_Partition_New dialog( devices[current_device],
*selected_partition_ptr,
any_extended,
new_count,
gparted_core.get_filesystems() );
dialog .set_transient_for( *this );
if ( dialog .run() == Gtk::RESPONSE_OK )
{
dialog .hide() ;
new_count++ ;
Operation * operation = new OperationCreate( devices[current_device],
*selected_partition_ptr,
dialog.Get_New_Partition() );
operation ->icon = render_icon( Gtk::Stock::NEW, Gtk::ICON_SIZE_MENU );
Add_Operation( operation );
Only allow Undo and Apply after merging operations (#699452) It was possible to make GParted crash by adding a label, check or new UUID operation and then applying the operation before the view of pending operations had finished fully opening. The operation would be successfully applied but GParted would crash afterwards. The fault was that Add_Operation() still enabled the Undo and Apply buttons and processed the GTK event loop before merging the list of pending operations. Faulty code flow went like this: activate_*() Add_Operation() Add operation to the operations[] vector Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Merge operations in the operations[] vector << Core dump here >> Merge_Operations() Refresh_Visual() This faulty code flow came about when merging of operations was added and it didn't appreciate that the operations[] vector could have been processed and cleared by Add_Operations() before the merge step. Relevant commit: b10349ae37df06b7bf7de91ea93a3913535ade3a Merge overlapping operations (#438573) Fragment of code in the label operation case: 2454 void Win_GParted::activate_label_partition() 2455 { ... 2472 Add_Operation( operation ) ; 2473 2474 // Verify if the two operations can be merged 2475 for ( unsigned int t = 0 ; t < operations .size() - 1 ; t++ ) 2476 { 2477 if ( operations[ t ] ->type == OPERATION_LABEL_PARTITION ) 2478 { 2479 if ( Merge_Operations( t, operations .size() - 1 ) ) 2480 break; 2481 } 2482 } Commentary in the crashing label operation case: 2472 The pending operation was already applied when Add_Operation() returned resulting in the operations[] vector being cleared setting its size to 0. 2475 The return type of operations.size() is an unsigned integral, so the upper limit of the for loop is t < 0UL - 1. Assuming a 32-bit machine that's t < 4294967295. 2477 operations[] vector is access from out of bounds offset 0 upwards until unallocated memory is accessed resulting in a core dump. Fix this by not enabling the Undo and Apply buttons and processing the GTK event loop until after merging of operations has been performed. Fixed code flow goes like this: activate_*() Add_Operation() Add operation to the operations[] vector Merge operations in the operations[] vector Merge_Operations() show_operationslist() Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Not allowing the operations list to be process until after the merge step is the be correct ordering. This also prevents the new operation from flashing up in the operations list and then immediately disappearing if merged. In the case of adding the first operation, delaying enabling the Undo and Apply buttons is enough as the buttons were previously disabled preventing the operation being applied before the merge. In the case of adding further operations, processing of the GTK event loop must also be delayed until after the merge to prevent the operations being applied before the merge. Although that window of opportunity would only be microseconds. Bug #699452 - Crash when applying operations before pending operations fully displayed
2013-05-17 10:01:42 -06:00
show_operationslist() ;
}
}
2004-09-19 14:24:53 -06:00
}
void Win_GParted::activate_delete()
{
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
// VGNAME from mount mount
if ( selected_partition_ptr->filesystem == FS_LVM2_PV && ! selected_partition_ptr->get_mountpoint().empty() )
{
if ( ! remove_non_empty_lvm2_pv_dialog( OPERATION_DELETE ) )
return ;
}
/* since logicals are *always* numbered from 5 to <last logical> there can be a shift
* in numbers after deletion.
* e.g. consider /dev/hda5 /dev/hda6 /dev/hda7. Now after removal of /dev/hda6,
* /dev/hda7 is renumbered to /dev/hda6
* the new situation is now /dev/hda5 /dev/hda6. If /dev/hda7 was mounted
* the OS cannot find /dev/hda7 anymore and the results aren't that pretty.
* It seems best to check for this and prohibit deletion with some explanation to the user.*/
if ( selected_partition_ptr->type == TYPE_LOGICAL &&
selected_partition_ptr->status != STAT_NEW &&
selected_partition_ptr->partition_number < devices[current_device].highest_busy )
{
Gtk::MessageDialog dialog( *this,
String::ucompose( _("Unable to delete %1!"), selected_partition_ptr->get_path() ),
false,
Gtk::MESSAGE_ERROR,
Gtk::BUTTONS_OK,
true );
dialog .set_secondary_text(
String::ucompose( _("Please unmount any logical partitions having a number higher than %1"),
selected_partition_ptr->partition_number ) );
dialog .run() ;
return;
2004-09-19 14:24:53 -06:00
}
//if partition is on the clipboard...(NOTE: we can't use Partition::== here..)
if ( copied_partition != NULL && selected_partition_ptr->get_path() == copied_partition->get_path() )
{
Gtk::MessageDialog dialog( *this,
String::ucompose( _("Are you sure you want to delete %1?"),
selected_partition_ptr->get_path() ),
false,
Gtk::MESSAGE_QUESTION,
Gtk::BUTTONS_NONE,
true );
dialog .set_secondary_text( _("After deletion this partition is no longer available for copying.") ) ;
/*TO TRANSLATORS: dialogtitle, looks like Delete /dev/hda2 (ntfs, 2345 MiB) */
dialog.set_title( String::ucompose( _("Delete %1 (%2, %3)"),
selected_partition_ptr->get_path(),
Utils::get_filesystem_string( selected_partition_ptr->filesystem ),
Utils::format_size( selected_partition_ptr->get_sector_length(), selected_partition_ptr->sector_size ) ) );
dialog .add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL );
dialog .add_button( Gtk::Stock::DELETE, Gtk::RESPONSE_OK );
dialog .show_all_children() ;
if ( dialog .run() != Gtk::RESPONSE_OK )
return ;
// Deleting partition on the clipboard. Clear clipboard.
delete copied_partition;
copied_partition = NULL;
}
// If deleted one is NEW, it doesn't make sense to add it to the operationslist,
// we erase its creation and possible modifications like resize etc.. from the operationslist.
// Calling Refresh_Visual will wipe every memory of its existence ;-)
if ( selected_partition_ptr->status == STAT_NEW )
{
//remove all operations done on this new partition (this includes creation)
for ( int t = 0 ; t < static_cast<int>( operations .size() ) ; t++ )
Prevent assert failure from OperationDelete::get_partition_new() (#767233) Composing these operations caused GParted to abort on an assert failure: (1) Delete an existing partition, (2) Create a new partition, (3) Delete new partition. This is the equivalent issue as fixed in the previous commit, except with the delete operation rather than the check operation: Prevent assert failure from OperationCheck::get_partition_new() (#767233) # ./gpartedbin ====================== libparted : 2.4 ====================== ** ERROR:OperationDelete.cc:41:virtual GParted::Partition& GParted::OperationDelete::get_partition_new(): assertion failed: (false) Aborted (core dumped) # gdb ./gpartedbin core.19232 --batch --quiet --ex backtrace -ex quit [New Thread 19232] [New Thread 19234] [Thread debugging using libthread_db enabled] Core was generated by `./gpartedbin'. Program terminated with signal 6, Aborted. #0 0x000000361f2325e5 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 64 return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); #0 0x000000361f2325e5 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 #1 0x000000361f233dc5 in abort () at abort.c:92 #2 0x0000003620a67324 in g_assertion_message (domain=<value optimized out>, file=<value optimized out>, line=<value optimized out>, func=0x50fcc0 "virtual GParted::Partition& GParted::OperationDelete::get_partition_new()", message=0x1b55f60 "assertion failed: (false)") at gtestutils.c:1358 #3 0x0000003620a678f0 in g_assertion_message_expr (domain=0x0, file=0x50fa68 "OperationDelete.cc", line=41, func=0x50fcc0 "virtual GParted::Partition& GParted::OperationDelete::get_partition_new()", expr=<value optimized out>) at gtestutils.c:1369 #4 0x000000000049aa0d in GParted::OperationDelete::get_partition_new (this=0x1b321b0) at OperationDelete.cc:41 #5 0x00000000004c6700 in GParted::Win_GParted::activate_delete (this=0x7ffc91403670) at Win_GParted.cc:2068 ... As before the crash is happened in Win_GParted::activate_delete() as it was going through the list of operations removing those which applied to the never created partition. It came across the delete operation of an existing partition and called get_partition_new(). As partition_new was not set or used by the delete operation this asserted false and crashed GParted. Unlike the check operation case, the delete operation doesn't have a partition afterwards. (As GParted represents unallocated space with partition objects then the delete operation could be populated with a new partition by constructing the correctly merged unallocated space partition object, but that is what OperationDelete::apply_to_visual() does and having a place holder doesn't seem like the right thing to do). Instead exclude delete operations, on existing partitions, when looking for operations applying to this not yet created partition as they are mutually exclusive. Bug 767233 - GParted core dump on assert failure in OperationDelete::get_partition_new()
2016-06-04 06:03:16 -06:00
if ( operations[t]->type != OPERATION_DELETE &&
operations[t]->get_partition_new().get_path() == selected_partition_ptr->get_path() )
remove_operation( t-- ) ;
//determine lowest possible new_count
new_count = 0 ;
for ( unsigned int t = 0 ; t < operations .size() ; t++ )
Prevent assert failure from OperationDelete::get_partition_new() (#767233) Composing these operations caused GParted to abort on an assert failure: (1) Delete an existing partition, (2) Create a new partition, (3) Delete new partition. This is the equivalent issue as fixed in the previous commit, except with the delete operation rather than the check operation: Prevent assert failure from OperationCheck::get_partition_new() (#767233) # ./gpartedbin ====================== libparted : 2.4 ====================== ** ERROR:OperationDelete.cc:41:virtual GParted::Partition& GParted::OperationDelete::get_partition_new(): assertion failed: (false) Aborted (core dumped) # gdb ./gpartedbin core.19232 --batch --quiet --ex backtrace -ex quit [New Thread 19232] [New Thread 19234] [Thread debugging using libthread_db enabled] Core was generated by `./gpartedbin'. Program terminated with signal 6, Aborted. #0 0x000000361f2325e5 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 64 return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); #0 0x000000361f2325e5 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 #1 0x000000361f233dc5 in abort () at abort.c:92 #2 0x0000003620a67324 in g_assertion_message (domain=<value optimized out>, file=<value optimized out>, line=<value optimized out>, func=0x50fcc0 "virtual GParted::Partition& GParted::OperationDelete::get_partition_new()", message=0x1b55f60 "assertion failed: (false)") at gtestutils.c:1358 #3 0x0000003620a678f0 in g_assertion_message_expr (domain=0x0, file=0x50fa68 "OperationDelete.cc", line=41, func=0x50fcc0 "virtual GParted::Partition& GParted::OperationDelete::get_partition_new()", expr=<value optimized out>) at gtestutils.c:1369 #4 0x000000000049aa0d in GParted::OperationDelete::get_partition_new (this=0x1b321b0) at OperationDelete.cc:41 #5 0x00000000004c6700 in GParted::Win_GParted::activate_delete (this=0x7ffc91403670) at Win_GParted.cc:2068 ... As before the crash is happened in Win_GParted::activate_delete() as it was going through the list of operations removing those which applied to the never created partition. It came across the delete operation of an existing partition and called get_partition_new(). As partition_new was not set or used by the delete operation this asserted false and crashed GParted. Unlike the check operation case, the delete operation doesn't have a partition afterwards. (As GParted represents unallocated space with partition objects then the delete operation could be populated with a new partition by constructing the correctly merged unallocated space partition object, but that is what OperationDelete::apply_to_visual() does and having a place holder doesn't seem like the right thing to do). Instead exclude delete operations, on existing partitions, when looking for operations applying to this not yet created partition as they are mutually exclusive. Bug 767233 - GParted core dump on assert failure in OperationDelete::get_partition_new()
2016-06-04 06:03:16 -06:00
if ( operations[t]->type != OPERATION_DELETE &&
operations[t]->get_partition_new().status == STAT_NEW &&
operations[t]->get_partition_new().partition_number > new_count )
new_count = operations[t]->get_partition_new().partition_number;
new_count += 1 ;
// After deleting all operations for the never applied partition creation,
// try to merge all remaining adjacent operations to catch any which are
// newly adjacent and can now be merged. (Applies to resize/move and
// format operations on real, already existing partitions which are only
// merged when adjacent).
merge_operations( MERGE_ALL_ADJACENT );
Refresh_Visual();
if ( ! operations .size() )
close_operationslist() ;
2004-09-19 14:24:53 -06:00
}
else //deletion of a real partition...
{
Operation * operation = new OperationDelete( devices[ current_device ], *selected_partition_ptr );
operation ->icon = render_icon( Gtk::Stock::DELETE, Gtk::ICON_SIZE_MENU ) ;
Add_Operation( operation ) ;
}
Only allow Undo and Apply after merging operations (#699452) It was possible to make GParted crash by adding a label, check or new UUID operation and then applying the operation before the view of pending operations had finished fully opening. The operation would be successfully applied but GParted would crash afterwards. The fault was that Add_Operation() still enabled the Undo and Apply buttons and processed the GTK event loop before merging the list of pending operations. Faulty code flow went like this: activate_*() Add_Operation() Add operation to the operations[] vector Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Merge operations in the operations[] vector << Core dump here >> Merge_Operations() Refresh_Visual() This faulty code flow came about when merging of operations was added and it didn't appreciate that the operations[] vector could have been processed and cleared by Add_Operations() before the merge step. Relevant commit: b10349ae37df06b7bf7de91ea93a3913535ade3a Merge overlapping operations (#438573) Fragment of code in the label operation case: 2454 void Win_GParted::activate_label_partition() 2455 { ... 2472 Add_Operation( operation ) ; 2473 2474 // Verify if the two operations can be merged 2475 for ( unsigned int t = 0 ; t < operations .size() - 1 ; t++ ) 2476 { 2477 if ( operations[ t ] ->type == OPERATION_LABEL_PARTITION ) 2478 { 2479 if ( Merge_Operations( t, operations .size() - 1 ) ) 2480 break; 2481 } 2482 } Commentary in the crashing label operation case: 2472 The pending operation was already applied when Add_Operation() returned resulting in the operations[] vector being cleared setting its size to 0. 2475 The return type of operations.size() is an unsigned integral, so the upper limit of the for loop is t < 0UL - 1. Assuming a 32-bit machine that's t < 4294967295. 2477 operations[] vector is access from out of bounds offset 0 upwards until unallocated memory is accessed resulting in a core dump. Fix this by not enabling the Undo and Apply buttons and processing the GTK event loop until after merging of operations has been performed. Fixed code flow goes like this: activate_*() Add_Operation() Add operation to the operations[] vector Merge operations in the operations[] vector Merge_Operations() show_operationslist() Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Not allowing the operations list to be process until after the merge step is the be correct ordering. This also prevents the new operation from flashing up in the operations list and then immediately disappearing if merged. In the case of adding the first operation, delaying enabling the Undo and Apply buttons is enough as the buttons were previously disabled preventing the operation being applied before the merge. In the case of adding further operations, processing of the GTK event loop must also be delayed until after the merge to prevent the operations being applied before the merge. Although that window of opportunity would only be microseconds. Bug #699452 - Crash when applying operations before pending operations fully displayed
2013-05-17 10:01:42 -06:00
show_operationslist() ;
2004-09-19 14:24:53 -06:00
}
void Win_GParted::activate_info()
2004-09-19 14:24:53 -06:00
{
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
Dialog_Partition_Info dialog( *selected_partition_ptr );
dialog .set_transient_for( *this );
dialog .run();
2004-09-19 14:24:53 -06:00
}
void Win_GParted::activate_format( GParted::FILESYSTEM new_fs )
2004-09-19 14:24:53 -06:00
{
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
// VGNAME from mount mount
if ( selected_partition_ptr->filesystem == FS_LVM2_PV && ! selected_partition_ptr->get_mountpoint().empty() )
{
if ( ! remove_non_empty_lvm2_pv_dialog( OPERATION_FORMAT ) )
return ;
}
//check for some limits...
fs = gparted_core .get_fs( new_fs ) ;
if ( ( selected_partition_ptr->get_byte_length() < fs.MIN ) ||
( fs.MAX && selected_partition_ptr->get_byte_length() > fs.MAX ) )
2004-09-19 14:24:53 -06:00
{
Gtk::MessageDialog dialog( *this,
String::ucompose(
/* TO TRANSLATORS: looks like
* Cannot format this file system to fat16.
*/
_( "Cannot format this file system to %1" ),
Utils::get_filesystem_string( new_fs ) ) ,
false,
Gtk::MESSAGE_ERROR,
Gtk::BUTTONS_OK,
true );
if ( selected_partition_ptr->get_byte_length() < fs.MIN )
dialog .set_secondary_text( String::ucompose(
/* TO TRANSLATORS: looks like
* A fat16 file system requires a partition of at least 16.00 MiB.
*/
_( "A %1 file system requires a partition of at least %2."),
2006-03-28 05:40:29 -07:00
Utils::get_filesystem_string( new_fs ),
Utils::format_size( fs .MIN, 1 /* Byte */ ) ) );
else
dialog .set_secondary_text( String::ucompose(
/* TO TRANSLATORS: looks like
* A partition with a hfs file system has a maximum size of 2.00 GiB.
*/
_( "A partition with a %1 file system has a maximum size of %2."),
2006-03-28 05:40:29 -07:00
Utils::get_filesystem_string( new_fs ),
Utils::format_size( fs .MAX, 1 /* Byte */ ) ) );
dialog .run() ;
return ;
2004-09-19 14:24:53 -06:00
}
//ok we made it. lets create an fitting partition object
Partition part_temp ;
part_temp.Set( devices[current_device].get_path(),
selected_partition_ptr->get_path(),
selected_partition_ptr->partition_number,
selected_partition_ptr->type,
selected_partition_ptr->whole_device,
new_fs,
selected_partition_ptr->sector_start,
selected_partition_ptr->sector_end,
devices[current_device].sector_size,
selected_partition_ptr->inside_extended,
false );
part_temp.name = selected_partition_ptr->name;
//Leave sector usage figures to new Partition object defaults of
// -1, -1, 0 (_used, _unused, _unallocated) representing unknown.
part_temp .status = GParted::STAT_FORMATTED ;
// When formatting a partition which already exists on the disk all possible
// operations could be pending so only try merging with the previous operation.
MergeType mergetype = MERGE_LAST_WITH_PREV;
// If selected partition is NEW we simply remove the NEW operation from the list and
// add it again with the new file system
if ( selected_partition_ptr->status == STAT_NEW )
2004-09-19 14:24:53 -06:00
{
part_temp.status = STAT_NEW;
// On a partition which is pending creation only resize/move and format
// operations are possible. These operations are always mergeable with
// the pending operation which will create the partition. Hence merge
// with any earlier operations to achieve this.
mergetype = MERGE_LAST_WITH_ANY;
2004-09-19 14:24:53 -06:00
}
Operation * operation = new OperationFormat( devices[current_device],
*selected_partition_ptr,
part_temp );
operation->icon = render_icon( Gtk::Stock::CONVERT, Gtk::ICON_SIZE_MENU );
Add_Operation( operation );
merge_operations( mergetype );
Only allow Undo and Apply after merging operations (#699452) It was possible to make GParted crash by adding a label, check or new UUID operation and then applying the operation before the view of pending operations had finished fully opening. The operation would be successfully applied but GParted would crash afterwards. The fault was that Add_Operation() still enabled the Undo and Apply buttons and processed the GTK event loop before merging the list of pending operations. Faulty code flow went like this: activate_*() Add_Operation() Add operation to the operations[] vector Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Merge operations in the operations[] vector << Core dump here >> Merge_Operations() Refresh_Visual() This faulty code flow came about when merging of operations was added and it didn't appreciate that the operations[] vector could have been processed and cleared by Add_Operations() before the merge step. Relevant commit: b10349ae37df06b7bf7de91ea93a3913535ade3a Merge overlapping operations (#438573) Fragment of code in the label operation case: 2454 void Win_GParted::activate_label_partition() 2455 { ... 2472 Add_Operation( operation ) ; 2473 2474 // Verify if the two operations can be merged 2475 for ( unsigned int t = 0 ; t < operations .size() - 1 ; t++ ) 2476 { 2477 if ( operations[ t ] ->type == OPERATION_LABEL_PARTITION ) 2478 { 2479 if ( Merge_Operations( t, operations .size() - 1 ) ) 2480 break; 2481 } 2482 } Commentary in the crashing label operation case: 2472 The pending operation was already applied when Add_Operation() returned resulting in the operations[] vector being cleared setting its size to 0. 2475 The return type of operations.size() is an unsigned integral, so the upper limit of the for loop is t < 0UL - 1. Assuming a 32-bit machine that's t < 4294967295. 2477 operations[] vector is access from out of bounds offset 0 upwards until unallocated memory is accessed resulting in a core dump. Fix this by not enabling the Undo and Apply buttons and processing the GTK event loop until after merging of operations has been performed. Fixed code flow goes like this: activate_*() Add_Operation() Add operation to the operations[] vector Merge operations in the operations[] vector Merge_Operations() show_operationslist() Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Not allowing the operations list to be process until after the merge step is the be correct ordering. This also prevents the new operation from flashing up in the operations list and then immediately disappearing if merged. In the case of adding the first operation, delaying enabling the Undo and Apply buttons is enough as the buttons were previously disabled preventing the operation being applied before the merge. In the case of adding further operations, processing of the GTK event loop must also be delayed until after the merge to prevent the operations being applied before the merge. Although that window of opportunity would only be microseconds. Bug #699452 - Crash when applying operations before pending operations fully displayed
2013-05-17 10:01:42 -06:00
show_operationslist() ;
2004-09-19 14:24:53 -06:00
}
void Win_GParted::unmount_partition( bool * succes, Glib::ustring * error )
{
std::vector<Glib::ustring> errors;
std::vector<Glib::ustring> failed_mountpoints;
std::vector<Glib::ustring> mountpoints = Mount_Info::get_all_mountpoints();
Glib::ustring dummy ;
*succes = true ;
for ( unsigned int t = 0 ; t < selected_partition_ptr->get_mountpoints().size() ; t++ )
if ( std::count( mountpoints.begin(),
mountpoints.end(),
selected_partition_ptr->get_mountpoints()[t] ) <= 1 )
{
Glib::ustring cmd = "umount -v \"" + selected_partition_ptr->get_mountpoints()[t] + "\"";
if ( Utils::execute_command( cmd, dummy, *error ) )
{
*succes = false ;
errors.push_back( "# " + cmd + "\n" + *error );
}
}
else
failed_mountpoints.push_back( selected_partition_ptr->get_mountpoints()[t] );
if ( *succes && failed_mountpoints .size() )
{
*succes = false ;
*error = _("The partition could not be unmounted from the following mount points:") ;
*error += "\n\n<i>" + Glib::build_path( "\n", failed_mountpoints ) + "</i>\n\n" ;
*error += _("Most likely other partitions are also mounted on these mount points. You are advised to unmount them manually.") ;
}
else
*error = "<i>" + Glib::build_path( "\n", errors ) + "</i>" ;
}
void Win_GParted::toggle_busy_state()
{
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
int operation_count = partition_in_operation_queue_count( *selected_partition_ptr );
bool success = false ;
Glib::ustring cmd;
Glib::ustring output;
Glib::ustring error;
if ( operation_count > 0 )
{
//Note that this situation will only occur when trying to swapon a partition
// or activate the Volume Group of a Physical Volume. This is because
// GParted does not permit queueing operations on partitions that are
// currently active (i.e., swap enabled, mounted or active VG). Hence
// this situation will not occur for the swapoff, unmount or deactivate VG
// actions that this method handles.
/*TO TRANSLATORS: Singular case looks like 1 operation is currently pending for partition /dev/sdd8. */
Glib::ustring tmp_msg =
String::ucompose( ngettext( "%1 operation is currently pending for partition %2"
, "%1 operations are currently pending for partition %2"
, operation_count
)
, operation_count
, selected_partition_ptr->get_path()
) ;
Gtk::MessageDialog dialog( *this
, tmp_msg
, false
, Gtk::MESSAGE_INFO
, Gtk::BUTTONS_OK
, true
) ;
if ( selected_partition_ptr->filesystem == FS_LINUX_SWAP )
{
tmp_msg = _( "The swapon action cannot be performed if an operation is pending for the partition." ) ;
tmp_msg += "\n" ;
tmp_msg += _( "Use the Edit menu to undo, clear, or apply operations before using swapon with this partition." ) ;
}
else if ( selected_partition_ptr->filesystem == FS_LVM2_PV )
{
tmp_msg = _( "The activate Volume Group action cannot be performed if an operation is pending for the partition." ) ;
tmp_msg += "\n" ;
tmp_msg += _( "Use the Edit menu to undo, clear, or apply operations before using activate Volume Group with this partition." ) ;
}
dialog .set_secondary_text( tmp_msg ) ;
dialog .run() ;
return ;
}
if ( selected_partition_ptr->filesystem == FS_LINUX_SWAP )
{
show_pulsebar(
String::ucompose(
selected_partition_ptr->busy ? _("Deactivating swap on %1") : _("Activating swap on %1"),
selected_partition_ptr->get_path() ) );
if ( selected_partition_ptr->busy )
cmd = "swapoff -v " + selected_partition_ptr->get_path();
else
cmd = "swapon -v " + selected_partition_ptr->get_path();
success = ! Utils::execute_command( cmd, output, error );
hide_pulsebar();
if ( ! success )
{
Gtk::MessageDialog dialog(
*this,
selected_partition_ptr->busy ? _("Could not deactivate swap") : _("Could not activate swap"),
false,
Gtk::MESSAGE_ERROR,
Gtk::BUTTONS_OK,
true ) ;
dialog.set_secondary_text( "# " + cmd + "\n" + error );
dialog.run() ;
}
}
else if ( selected_partition_ptr->filesystem == FS_LVM2_PV )
{
show_pulsebar(
String::ucompose(
selected_partition_ptr->busy ? _("Deactivating Volume Group %1")
: _("Activating Volume Group %1"),
// VGNAME from mount point
selected_partition_ptr->get_mountpoint() ) );
if ( selected_partition_ptr->busy )
// VGNAME from mount point
cmd = "lvm vgchange -a n " + selected_partition_ptr->get_mountpoint();
else
cmd = "lvm vgchange -a y " + selected_partition_ptr->get_mountpoint();
success = ! Utils::execute_command( cmd, output, error );
hide_pulsebar();
if ( ! success )
{
Gtk::MessageDialog dialog(
*this,
selected_partition_ptr->busy ? _("Could not deactivate Volume Group")
: _("Could not activate Volume Group"),
false,
Gtk::MESSAGE_ERROR,
Gtk::BUTTONS_OK,
true ) ;
dialog.set_secondary_text( "# " + cmd + "\n" + error );
dialog.run() ;
}
}
else if ( selected_partition_ptr->busy )
{
show_pulsebar( String::ucompose( _("Unmounting %1"), selected_partition_ptr->get_path() ) );
unmount_partition( &success, &error );
hide_pulsebar();
if ( ! success )
{
Gtk::MessageDialog dialog( *this,
String::ucompose( _("Could not unmount %1"),
selected_partition_ptr->get_path() ),
false,
Gtk::MESSAGE_ERROR,
Gtk::BUTTONS_OK,
true );
dialog .set_secondary_text( error, true ) ;
dialog.run() ;
}
}
menu_gparted_refresh_devices() ;
}
void Win_GParted::activate_mount_partition( unsigned int index )
{
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
int operation_count = partition_in_operation_queue_count( *selected_partition_ptr );
if ( operation_count > 0 )
{
/*TO TRANSLATORS: Plural case looks like 4 operations are currently pending for partition /dev/sdd8. */
Glib::ustring tmp_msg =
String::ucompose( ngettext( "%1 operation is currently pending for partition %2"
, "%1 operations are currently pending for partition %2"
, operation_count
)
, operation_count
, selected_partition_ptr->get_path()
) ;
Gtk::MessageDialog dialog( *this
, tmp_msg
, false
, Gtk::MESSAGE_INFO
, Gtk::BUTTONS_OK
, true
) ;
tmp_msg = _( "The mount action cannot be performed if an operation is pending for the partition." ) ;
tmp_msg += "\n" ;
tmp_msg += _( "Use the Edit menu to undo, clear, or apply operations before using mount with this partition." ) ;
dialog .set_secondary_text( tmp_msg ) ;
dialog .run() ;
return ;
}
bool success = false ;
Glib::ustring cmd;
Glib::ustring output;
Glib::ustring error;
Glib::ustring message;
show_pulsebar( String::ucompose( _("mounting %1 on %2"),
selected_partition_ptr->get_path(),
selected_partition_ptr->get_mountpoints()[index] ) );
// First try mounting letting mount (libblkid) determine the file system type.
cmd = "mount -v " + selected_partition_ptr->get_path() +
" \"" + selected_partition_ptr->get_mountpoints()[index] + "\"";
success = ! Utils::execute_command( cmd, output, error );
if ( ! success )
{
message = "# " + cmd + "\n" + error;
Glib::ustring type = Utils::get_filesystem_kernel_name( selected_partition_ptr->filesystem );
if ( ! type.empty() )
{
// Second try mounting specifying the GParted determined file
// system type.
cmd = "mount -v -t " + type + " " + selected_partition_ptr->get_path() +
" \"" + selected_partition_ptr->get_mountpoints()[index] + "\"";
success = ! Utils::execute_command( cmd, output, error );
if ( ! success )
message += "\n# " + cmd + "\n" + error;
}
}
hide_pulsebar();
if ( ! success )
{
Gtk::MessageDialog dialog( *this,
String::ucompose( _("Could not mount %1 on %2"),
selected_partition_ptr->get_path(),
selected_partition_ptr->get_mountpoints()[index] ),
false,
Gtk::MESSAGE_ERROR,
Gtk::BUTTONS_OK,
true );
dialog.set_secondary_text( message );
dialog.run() ;
}
menu_gparted_refresh_devices() ;
}
void Win_GParted::activate_disklabel()
{
//If there are active mounted partitions on the device then warn
// the user that all partitions must be unactive before creating
// a new partition table
int active_count = active_partitions_on_device_count( devices[ current_device ] ) ;
if ( active_count > 0 )
{
Glib::ustring tmp_msg =
String::ucompose( /*TO TRANSLATORS: Singular case looks like 1 partition is currently active on device /dev/sda */
ngettext( "%1 partition is currently active on device %2"
/*TO TRANSLATORS: Plural case looks like 3 partitions are currently active on device /dev/sda */
, "%1 partitions are currently active on device %2"
, active_count
)
, active_count
, devices[ current_device ] .get_path()
) ;
Gtk::MessageDialog dialog( *this
, tmp_msg
, false
, Gtk::MESSAGE_INFO
, Gtk::BUTTONS_OK
, true
) ;
tmp_msg = _( "A new partition table cannot be created when there are active partitions." ) ;
tmp_msg += " " ;
tmp_msg += _( "Active partitions are those that are in use, such as a mounted file system, or enabled swap space." ) ;
tmp_msg += "\n" ;
tmp_msg += _( "Use Partition menu options, such as unmount or swapoff, to deactivate all partitions on this device before creating a new partition table." ) ;
dialog .set_secondary_text( tmp_msg ) ;
dialog .run() ;
return ;
}
//If there are pending operations then warn the user that these
// operations must either be applied or cleared before creating
// a new partition table.
if ( operations .size() )
{
Glib::ustring tmp_msg =
String::ucompose( ngettext( "%1 operation is currently pending"
, "%1 operations are currently pending"
, operations .size()
)
, operations .size()
) ;
Gtk::MessageDialog dialog( *this
, tmp_msg
, false
, Gtk::MESSAGE_INFO
, Gtk::BUTTONS_OK
, true
) ;
tmp_msg = _( "A new partition table cannot be created when there are pending operations." ) ;
tmp_msg += "\n" ;
tmp_msg += _( "Use the Edit menu to either clear or apply all operations before creating a new partition table." ) ;
dialog .set_secondary_text( tmp_msg ) ;
dialog .run() ;
return ;
}
//Display dialog for creating a new partition table.
Dialog_Disklabel dialog( devices[ current_device ] ) ;
dialog .set_transient_for( *this );
if ( dialog .run() == Gtk::RESPONSE_APPLY )
{
if ( ! gparted_core.set_disklabel( devices[current_device], dialog.Get_Disklabel() ) )
{
Gtk::MessageDialog dialog( *this,
_("Error while creating partition table"),
true,
Gtk::MESSAGE_ERROR,
Gtk::BUTTONS_OK,
true ) ;
dialog .run() ;
}
dialog .hide() ;
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();
/*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()));
gpart_output="";
gparted_core.guess_partition_table(devices[ current_device ], gpart_output);
hide_pulsebar();
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.found_partitions() )
{
//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()
{
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
get_window() ->set_cursor( Gdk::Cursor( Gdk::WATCH ) ) ;
while ( Gtk::Main::events_pending() )
Gtk::Main::iteration() ;
DialogManageFlags dialog( *selected_partition_ptr, gparted_core.get_available_flags( *selected_partition_ptr ) );
dialog .set_transient_for( *this ) ;
dialog .signal_get_flags .connect(
sigc::mem_fun( &gparted_core, &GParted_Core::get_available_flags ) ) ;
dialog .signal_toggle_flag .connect(
sigc::mem_fun( &gparted_core, &GParted_Core::toggle_flag ) ) ;
get_window() ->set_cursor() ;
dialog .run() ;
dialog .hide() ;
if ( dialog .any_change )
menu_gparted_refresh_devices() ;
}
void Win_GParted::activate_check()
{
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
Prevent assert failure from OperationCheck::get_partition_new() (#767233) Composing these operations caused GParted to abort on an assert failure: (1) Check an existing partition, (2) Create a new partition, (3) Delete new partition. # ./gpartedbin ====================== libparted : 2.4 ====================== ** ERROR:OperationCheck.cc:40:virtual GParted::Partition& GParted::OperationCheck::get_partition_new(): assertion failed: (false) Aborted (core dumped) # gdb ./gpartedbin core.8876 --batch --quiet --ex backtrace -ex quit [New Thread 8876] [New Thread 8879] [Thread debugging using libthread_db enabled] Core was generated by `./gpartedbin'. Program terminated with signal 6, Aborted. #0 0x000000361f2325e5 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 64 return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); #0 0x000000361f2325e5 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 #1 0x000000361f233dc5 in abort () at abort.c:92 #2 0x0000003620a67324 in g_assertion_message (domain=<value optimized out>, file=<value optimized out>, line=<value optimized out>, func=0x50f400 "virtual GParted::Partition& GParted::OperationCheck::get_partition_new()", message=0x1d37a00 "assertion failed: (false)") at gtestutils.c:1358 #3 0x0000003620a678f0 in g_assertion_message_expr (domain=0x0, file=0x50f1a8 "OperationCheck.cc", line=40, func=0x50f400 "virtual GParted::Partition& GParted::OperationCheck::get_partition_new()", expr=<value optimized out>) at gtestutils.c:1369 #4 0x0000000000498e21 in GParted::OperationCheck::get_partition_new (this=0x1d1bb30) at OperationCheck.cc:40 #5 0x00000000004c66ec in GParted::Win_GParted::activate_delete (this=0x7fff031c3e30) at Win_GParted.cc:2068 ... When Win_GParted::activate_delete() was stepping through the operation list removing operations (2 & 3 in the above recreation steps) which related to the new partition never to be created it called get_partition_new() on all operations in the list. This included calling get_partition_new() on the check operation (1 in the above recreation steps). As partition_new was not set or used by the check operation get_partition_new() asserted false and crashed GParted. Fix by populating the partition_new member in OperationCheck objects, thus allowing get_partition_new() to be called on the object. As a check operation doesn't change any partition boundaries or file system attributes, just duplicate the new partition from the original partition. Bug 767233 - GParted core dump on assert failure in OperationDelete::get_partition_new()
2016-06-04 02:26:22 -06:00
// FIXME: Consider constructing new partition object with zero unallocated and
// messages cleared to represent how applying a check operation also grows the
// file system to fill the partition.
Operation * operation = new OperationCheck( devices[current_device], *selected_partition_ptr );
operation ->icon = render_icon( Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU );
Add_Operation( operation ) ;
// Try to merge this check operation with all previous operations.
merge_operations( MERGE_LAST_WITH_ANY );
Only allow Undo and Apply after merging operations (#699452) It was possible to make GParted crash by adding a label, check or new UUID operation and then applying the operation before the view of pending operations had finished fully opening. The operation would be successfully applied but GParted would crash afterwards. The fault was that Add_Operation() still enabled the Undo and Apply buttons and processed the GTK event loop before merging the list of pending operations. Faulty code flow went like this: activate_*() Add_Operation() Add operation to the operations[] vector Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Merge operations in the operations[] vector << Core dump here >> Merge_Operations() Refresh_Visual() This faulty code flow came about when merging of operations was added and it didn't appreciate that the operations[] vector could have been processed and cleared by Add_Operations() before the merge step. Relevant commit: b10349ae37df06b7bf7de91ea93a3913535ade3a Merge overlapping operations (#438573) Fragment of code in the label operation case: 2454 void Win_GParted::activate_label_partition() 2455 { ... 2472 Add_Operation( operation ) ; 2473 2474 // Verify if the two operations can be merged 2475 for ( unsigned int t = 0 ; t < operations .size() - 1 ; t++ ) 2476 { 2477 if ( operations[ t ] ->type == OPERATION_LABEL_PARTITION ) 2478 { 2479 if ( Merge_Operations( t, operations .size() - 1 ) ) 2480 break; 2481 } 2482 } Commentary in the crashing label operation case: 2472 The pending operation was already applied when Add_Operation() returned resulting in the operations[] vector being cleared setting its size to 0. 2475 The return type of operations.size() is an unsigned integral, so the upper limit of the for loop is t < 0UL - 1. Assuming a 32-bit machine that's t < 4294967295. 2477 operations[] vector is access from out of bounds offset 0 upwards until unallocated memory is accessed resulting in a core dump. Fix this by not enabling the Undo and Apply buttons and processing the GTK event loop until after merging of operations has been performed. Fixed code flow goes like this: activate_*() Add_Operation() Add operation to the operations[] vector Merge operations in the operations[] vector Merge_Operations() show_operationslist() Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Not allowing the operations list to be process until after the merge step is the be correct ordering. This also prevents the new operation from flashing up in the operations list and then immediately disappearing if merged. In the case of adding the first operation, delaying enabling the Undo and Apply buttons is enough as the buttons were previously disabled preventing the operation being applied before the merge. In the case of adding further operations, processing of the GTK event loop must also be delayed until after the merge to prevent the operations being applied before the merge. Although that window of opportunity would only be microseconds. Bug #699452 - Crash when applying operations before pending operations fully displayed
2013-05-17 10:01:42 -06:00
show_operationslist() ;
}
void Win_GParted::activate_label_filesystem()
{
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
Dialog_FileSystem_Label dialog( *selected_partition_ptr );
dialog .set_transient_for( *this );
if ( dialog .run() == Gtk::RESPONSE_OK
&& dialog.get_new_label() != selected_partition_ptr->get_filesystem_label() )
{
dialog .hide() ;
// Make a duplicate of the selected partition (used in UNDO)
Partition * part_temp = selected_partition_ptr->clone();
part_temp->set_filesystem_label( dialog.get_new_label() );
Operation * operation = new OperationLabelFileSystem( devices[current_device],
*selected_partition_ptr, *part_temp );
operation ->icon = render_icon( Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU );
delete part_temp;
part_temp = NULL;
Add_Operation( operation ) ;
// Try to merge this label file system operation with all previous
// operations.
merge_operations( MERGE_LAST_WITH_ANY );
Only allow Undo and Apply after merging operations (#699452) It was possible to make GParted crash by adding a label, check or new UUID operation and then applying the operation before the view of pending operations had finished fully opening. The operation would be successfully applied but GParted would crash afterwards. The fault was that Add_Operation() still enabled the Undo and Apply buttons and processed the GTK event loop before merging the list of pending operations. Faulty code flow went like this: activate_*() Add_Operation() Add operation to the operations[] vector Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Merge operations in the operations[] vector << Core dump here >> Merge_Operations() Refresh_Visual() This faulty code flow came about when merging of operations was added and it didn't appreciate that the operations[] vector could have been processed and cleared by Add_Operations() before the merge step. Relevant commit: b10349ae37df06b7bf7de91ea93a3913535ade3a Merge overlapping operations (#438573) Fragment of code in the label operation case: 2454 void Win_GParted::activate_label_partition() 2455 { ... 2472 Add_Operation( operation ) ; 2473 2474 // Verify if the two operations can be merged 2475 for ( unsigned int t = 0 ; t < operations .size() - 1 ; t++ ) 2476 { 2477 if ( operations[ t ] ->type == OPERATION_LABEL_PARTITION ) 2478 { 2479 if ( Merge_Operations( t, operations .size() - 1 ) ) 2480 break; 2481 } 2482 } Commentary in the crashing label operation case: 2472 The pending operation was already applied when Add_Operation() returned resulting in the operations[] vector being cleared setting its size to 0. 2475 The return type of operations.size() is an unsigned integral, so the upper limit of the for loop is t < 0UL - 1. Assuming a 32-bit machine that's t < 4294967295. 2477 operations[] vector is access from out of bounds offset 0 upwards until unallocated memory is accessed resulting in a core dump. Fix this by not enabling the Undo and Apply buttons and processing the GTK event loop until after merging of operations has been performed. Fixed code flow goes like this: activate_*() Add_Operation() Add operation to the operations[] vector Merge operations in the operations[] vector Merge_Operations() show_operationslist() Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Not allowing the operations list to be process until after the merge step is the be correct ordering. This also prevents the new operation from flashing up in the operations list and then immediately disappearing if merged. In the case of adding the first operation, delaying enabling the Undo and Apply buttons is enough as the buttons were previously disabled preventing the operation being applied before the merge. In the case of adding further operations, processing of the GTK event loop must also be delayed until after the merge to prevent the operations being applied before the merge. Although that window of opportunity would only be microseconds. Bug #699452 - Crash when applying operations before pending operations fully displayed
2013-05-17 10:01:42 -06:00
show_operationslist() ;
}
}
void Win_GParted::activate_name_partition()
{
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
Dialog_Partition_Name dialog( *selected_partition_ptr,
devices[current_device].get_max_partition_name_length() );
dialog.set_transient_for( *this );
if ( dialog.run() == Gtk::RESPONSE_OK
&& dialog.get_new_name() != selected_partition_ptr->name )
{
dialog.hide();
// Make a duplicate of the selected partition (used in UNDO)
Partition * part_temp = selected_partition_ptr->clone();
part_temp->name = dialog.get_new_name();
Operation * operation = new OperationNamePartition( devices[current_device],
*selected_partition_ptr, *part_temp );
operation->icon = render_icon( Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU );
delete part_temp;
part_temp = NULL;
Add_Operation( operation );
// Try to merge this name partition operation with all previous
// operations.
merge_operations( MERGE_LAST_WITH_ANY );
show_operationslist();
}
}
void Win_GParted::activate_change_uuid()
{
g_assert( selected_partition_ptr != NULL ); // Bug: Partition callback without a selected partition
g_assert( valid_display_partition_ptr( selected_partition_ptr ) ); // Bug: Not pointing at a valid display partition object
const FileSystem * filesystem_object = gparted_core.get_filesystem_object( selected_partition_ptr->filesystem );
if ( filesystem_object->get_custom_text( CTEXT_CHANGE_UUID_WARNING ) != "" )
{
int i ;
Gtk::MessageDialog dialog( *this,
filesystem_object->get_custom_text( CTEXT_CHANGE_UUID_WARNING, 0 ),
false,
Gtk::MESSAGE_WARNING,
Gtk::BUTTONS_OK,
true );
Glib::ustring tmp_msg = "" ;
for ( i = 1 ; filesystem_object->get_custom_text( CTEXT_CHANGE_UUID_WARNING, i ) != "" ; i++ )
{
if ( i > 1 )
tmp_msg += "\n\n" ;
tmp_msg += filesystem_object->get_custom_text( CTEXT_CHANGE_UUID_WARNING, i );
}
dialog .set_secondary_text( tmp_msg ) ;
dialog .run() ;
}
// Make a duplicate of the selected partition (used in UNDO)
Partition * part_temp = selected_partition_ptr->clone();
if ( part_temp->filesystem == FS_NTFS )
//Explicitly ask for half, so that the user will be aware of it
//Also, keep this kind of policy out of the NTFS code.
part_temp->uuid = UUID_RANDOM_NTFS_HALF;
else
part_temp->uuid = UUID_RANDOM;
Operation * operation = new OperationChangeUUID( devices[current_device],
*selected_partition_ptr, *part_temp );
operation ->icon = render_icon( Gtk::Stock::EXECUTE, Gtk::ICON_SIZE_MENU );
delete part_temp;
part_temp = NULL;
Add_Operation( operation ) ;
// Try to merge this change UUID operation with all previous operations.
merge_operations( MERGE_LAST_WITH_ANY );
Only allow Undo and Apply after merging operations (#699452) It was possible to make GParted crash by adding a label, check or new UUID operation and then applying the operation before the view of pending operations had finished fully opening. The operation would be successfully applied but GParted would crash afterwards. The fault was that Add_Operation() still enabled the Undo and Apply buttons and processed the GTK event loop before merging the list of pending operations. Faulty code flow went like this: activate_*() Add_Operation() Add operation to the operations[] vector Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Merge operations in the operations[] vector << Core dump here >> Merge_Operations() Refresh_Visual() This faulty code flow came about when merging of operations was added and it didn't appreciate that the operations[] vector could have been processed and cleared by Add_Operations() before the merge step. Relevant commit: b10349ae37df06b7bf7de91ea93a3913535ade3a Merge overlapping operations (#438573) Fragment of code in the label operation case: 2454 void Win_GParted::activate_label_partition() 2455 { ... 2472 Add_Operation( operation ) ; 2473 2474 // Verify if the two operations can be merged 2475 for ( unsigned int t = 0 ; t < operations .size() - 1 ; t++ ) 2476 { 2477 if ( operations[ t ] ->type == OPERATION_LABEL_PARTITION ) 2478 { 2479 if ( Merge_Operations( t, operations .size() - 1 ) ) 2480 break; 2481 } 2482 } Commentary in the crashing label operation case: 2472 The pending operation was already applied when Add_Operation() returned resulting in the operations[] vector being cleared setting its size to 0. 2475 The return type of operations.size() is an unsigned integral, so the upper limit of the for loop is t < 0UL - 1. Assuming a 32-bit machine that's t < 4294967295. 2477 operations[] vector is access from out of bounds offset 0 upwards until unallocated memory is accessed resulting in a core dump. Fix this by not enabling the Undo and Apply buttons and processing the GTK event loop until after merging of operations has been performed. Fixed code flow goes like this: activate_*() Add_Operation() Add operation to the operations[] vector Merge operations in the operations[] vector Merge_Operations() show_operationslist() Enable Undo and Apply buttons Refresh_Visual() Process GTK event loop Process Apply button callback applying operations, refreshing display and clearing operations[] vector Not allowing the operations list to be process until after the merge step is the be correct ordering. This also prevents the new operation from flashing up in the operations list and then immediately disappearing if merged. In the case of adding the first operation, delaying enabling the Undo and Apply buttons is enough as the buttons were previously disabled preventing the operation being applied before the merge. In the case of adding further operations, processing of the GTK event loop must also be delayed until after the merge to prevent the operations being applied before the merge. Although that window of opportunity would only be microseconds. Bug #699452 - Crash when applying operations before pending operations fully displayed
2013-05-17 10:01:42 -06:00
show_operationslist() ;
}
void Win_GParted::activate_undo()
2004-09-19 14:24:53 -06:00
{
//when undoing a creation it's safe to decrease the newcount by one
if ( operations .back() ->type == OPERATION_CREATE )
2004-10-06 09:32:40 -06:00
new_count-- ;
remove_operation() ;
Refresh_Visual();
if ( ! operations .size() )
close_operationslist() ;
//FIXME: A slight flicker may be introduced by this extra display refresh.
//An extra display refresh seems to prevent the disk area visual disk from
// disappearing when there enough operations to require a scrollbar
// (about 4+ operations with default window size) and a user clicks on undo.
// See also Win_GParted::Add_operation().
drawingarea_visualdisk .queue_draw() ;
2004-09-19 14:24:53 -06:00
}
void Win_GParted::remove_operation( int index, bool remove_all )
{
if ( remove_all )
{
for ( unsigned int t = 0 ; t < operations .size() ; t++ )
delete operations[ t ] ;
operations .clear() ;
}
else if ( index == -1 && operations .size() > 0 )
{
delete operations .back() ;
operations .pop_back() ;
}
else if ( index > -1 && index < static_cast<int>( operations .size() ) )
{
delete operations[ index ] ;
operations .erase( operations .begin() + index ) ;
}
}
2004-09-19 14:24:53 -06:00
int Win_GParted::partition_in_operation_queue_count( const Partition & partition )
{
int operation_count = 0 ;
for ( unsigned int t = 0 ; t < operations .size() ; t++ )
{
if ( partition.get_path() == operations[t]->get_partition_original().get_path() )
operation_count++ ;
}
return operation_count ;
}
int Win_GParted::active_partitions_on_device_count( const Device & device )
{
int active_count = 0 ;
//Count the active partitions on the device
for ( unsigned int k=0; k < device .partitions .size(); k++ )
{
// Count the active primary and extended partitions
if ( device .partitions[ k ] .busy
&& device .partitions[ k ] .type != TYPE_UNALLOCATED
)
active_count++ ;
//Count the active logical partitions
if ( device .partitions[ k ] .busy
&& device .partitions[ k ] .type == TYPE_EXTENDED
)
{
for ( unsigned int j=0; j < device .partitions[ k ] .logicals .size(); j++ )
{
if ( device .partitions[ k ] .logicals [ j ] .busy
&& device .partitions[ k ] .logicals [ j ] .type != TYPE_UNALLOCATED
)
active_count++ ;
}
}
}
return active_count ;
}
void Win_GParted::activate_apply()
2004-09-19 14:24:53 -06:00
{
Gtk::MessageDialog dialog( *this,
_("Are you sure you want to apply the pending operations?"),
false,
Gtk::MESSAGE_WARNING,
Gtk::BUTTONS_NONE,
true );
Glib::ustring temp;
temp = _( "Editing partitions has the potential to cause LOSS of DATA.") ;
temp += "\n" ;
temp += _( "You are advised to backup your data before proceeding." ) ;
dialog .set_secondary_text( temp ) ;
dialog .set_title( _( "Apply operations to device" ) );
dialog .add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL );
dialog .add_button( Gtk::Stock::APPLY, Gtk::RESPONSE_OK );
dialog .show_all_children() ;
if ( dialog.run() == Gtk::RESPONSE_OK )
2004-09-19 14:24:53 -06:00
{
dialog .hide() ; //hide confirmationdialog
Dialog_Progress dialog_progress( operations ) ;
dialog_progress .set_transient_for( *this ) ;
dialog_progress .signal_apply_operation .connect(
sigc::mem_fun(gparted_core, &GParted_Core::apply_operation_to_disk) ) ;
dialog_progress .signal_get_libparted_version .connect(
sigc::mem_fun(gparted_core, &GParted_Core::get_libparted_version) ) ;
int response ;
do
{
response = dialog_progress .run() ;
}
while ( response == Gtk::RESPONSE_CANCEL || response == Gtk::RESPONSE_OK ) ;
dialog_progress .hide() ;
2004-09-19 14:24:53 -06:00
//wipe operations...
remove_operation( -1, true ) ;
hbox_operations .clear() ;
close_operationslist() ;
//reset new_count to 1
new_count = 1 ;
2004-09-19 14:24:53 -06:00
//reread devices and their layouts...
menu_gparted_refresh_devices() ;
2004-09-19 14:24:53 -06:00
}
}
bool Win_GParted::remove_non_empty_lvm2_pv_dialog( const OperationType optype )
{
Glib::ustring tmp_msg ;
switch ( optype )
{
case OPERATION_DELETE:
tmp_msg = String::ucompose( _( "You are deleting non-empty LVM2 Physical Volume %1" ),
selected_partition_ptr->get_path() );
break ;
case OPERATION_FORMAT:
tmp_msg = String::ucompose( _( "You are formatting over non-empty LVM2 Physical Volume %1" ),
selected_partition_ptr->get_path() );
break ;
case OPERATION_COPY:
tmp_msg = String::ucompose( _( "You are pasting over non-empty LVM2 Physical Volume %1" ),
selected_partition_ptr->get_path() );
break ;
default:
break ;
}
Gtk::MessageDialog dialog( *this, tmp_msg,
false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE, true ) ;
tmp_msg = _( "Deleting or overwriting the Physical Volume is irrecoverable and will destroy or damage the "
" Volume Group." ) ;
tmp_msg += "\n\n" ;
tmp_msg += _( "To avoid destroying or damaging the Volume Group, you are advised to cancel and use external "
"LVM commands to free the Physical Volume before attempting this operation." ) ;
tmp_msg += "\n\n" ;
tmp_msg += _( "Do you want to continue to forcibly delete the Physical Volume?" ) ;
Glib::ustring vgname = LVM2_PV_Info::get_vg_name( selected_partition_ptr->get_path() );
std::vector<Glib::ustring> members ;
if ( ! vgname .empty() )
members = LVM2_PV_Info::get_vg_members( vgname );
//Single copy of each string for translation purposes
const Glib::ustring vgname_label = _( "Volume Group:" ) ;
const Glib::ustring members_label = _( "Members:" ) ;
#ifndef HAVE_GET_MESSAGE_AREA
//Basic method of displaying VG members by appending it to the secondary text in the dialog.
tmp_msg += "\n____________________\n\n" ;
tmp_msg += "<b>" ;
tmp_msg += vgname_label ;
tmp_msg += "</b> " ;
tmp_msg += vgname ;
tmp_msg += "\n" ;
tmp_msg += "<b>" ;
tmp_msg += members_label ;
tmp_msg += "</b>" ;
if ( ! members .empty() )
{
tmp_msg += " " ;
tmp_msg += members [0] ;
for ( unsigned int i = 1 ; i < members .size() ; i ++ )
{
tmp_msg += " " ;
tmp_msg += members [i] ;
}
}
#endif /* ! HAVE_GET_MESSAGE_AREA */
dialog .set_secondary_text( tmp_msg, true ) ;
#ifdef HAVE_GET_MESSAGE_AREA
//Nicely formatted method of displaying VG members by using a table below the secondary text
// in the dialog. Uses Gtk::MessageDialog::get_message_area() which was new in gtkmm-2.22
// released September 2010.
Gtk::Box * msg_area = dialog .get_message_area() ;
Gtk::HSeparator * hsep( manage( new Gtk::HSeparator() ) ) ;
msg_area ->pack_start( * hsep ) ;
Gtk::Table * table( manage( new Gtk::Table() ) ) ;
table ->set_border_width( 0 ) ;
table ->set_col_spacings( 10 ) ;
msg_area ->pack_start( * table ) ;
int top = 0, bottom = 1 ;
//Volume Group
table ->attach( * Utils::mk_label( "<b>" + Glib::ustring( vgname_label ) + "</b>" ),
0, 1, top, bottom, Gtk::FILL ) ;
table ->attach( * Utils::mk_label( vgname, true, false, true ),
1, 2, top++, bottom++, Gtk::FILL ) ;
//Members
table ->attach( * Utils::mk_label( "<b>" + Glib::ustring( members_label ) + "</b>",
true, false, false, 0.0 /* ALIGN_TOP */ ),
0, 1, top, bottom, Gtk::FILL ) ;
Glib::ustring members_str = "" ;
if ( ! members .empty() )
{
for ( unsigned int i = 0 ; i < members .size() ; i ++ )
{
if ( i > 0 )
members_str += "\n" ;
members_str += members[i] ;
}
}
table ->attach( * Utils::mk_label( members_str, true, false, true, 0.0 /* ALIGN_TOP */ ),
1, 2, top++, bottom++, Gtk::FILL ) ;
#endif /* HAVE_GET_MESSAGE_AREA */
dialog .add_button( Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL );
dialog .add_button( Gtk::Stock::DELETE, Gtk::RESPONSE_OK );
dialog .show_all() ;
if ( dialog .run() == Gtk::RESPONSE_OK )
return true ;
return false ;
}
2004-09-19 14:24:53 -06:00
} // GParted