1
/* Copyright (C) 2004 Bart 'plors' Hakvoort
2
* Copyright (C) 2008, 2009, 2010, 2011, 2012 Curtis Gedak
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU Library General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
#include "../include/Win_GParted.h"
20
#include "../include/GParted_Core.h"
21
#include "../include/DMRaid.h"
22
#include "../include/SWRaid.h"
23
#include "../include/FS_Info.h"
24
#include "../include/LVM2_PV_Info.h"
25
#include "../include/OperationCopy.h"
26
#include "../include/OperationCreate.h"
27
#include "../include/OperationDelete.h"
28
#include "../include/OperationFormat.h"
29
#include "../include/OperationResizeMove.h"
30
#include "../include/OperationChangeUUID.h"
31
#include "../include/OperationLabelPartition.h"
32
#include "../include/Proc_Partitions_Info.h"
34
#include "../include/btrfs.h"
35
#include "../include/exfat.h"
36
#include "../include/ext2.h"
37
#include "../include/ext3.h"
38
#include "../include/ext4.h"
39
#include "../include/fat16.h"
40
#include "../include/fat32.h"
41
#include "../include/linux_swap.h"
42
#include "../include/lvm2_pv.h"
43
#include "../include/reiserfs.h"
44
#include "../include/nilfs2.h"
45
#include "../include/ntfs.h"
46
#include "../include/xfs.h"
47
#include "../include/jfs.h"
48
#include "../include/hfs.h"
49
#include "../include/hfsplus.h"
50
#include "../include/reiser4.h"
51
#include "../include/ufs.h"
55
#include <sys/statvfs.h>
56
#include <sys/types.h>
61
#include <gtkmm/messagedialog.h>
63
std::vector<Glib::ustring> libparted_messages ; //see ped_exception_handler()
68
GParted_Core::GParted_Core()
74
thread_status_message = "" ;
76
ped_exception_set_handler( ped_exception_handler ) ;
79
for ( PedPartitionFlag flag = ped_partition_flag_next( static_cast<PedPartitionFlag>( NULL ) ) ;
81
flag = ped_partition_flag_next( flag ) )
82
flags .push_back( flag ) ;
84
//throw libpartedversion to the stdout to see which version is actually used.
85
std::cout << "======================" << std::endl ;
86
std::cout << "libparted : " << ped_get_version() << std::endl ;
87
std::cout << "======================" << std::endl ;
89
//initialize file system list
90
find_supported_filesystems() ;
93
void GParted_Core::find_supported_filesystems()
95
std::map< FILESYSTEM, FileSystem * >::iterator f ;
97
// TODO: determine whether it is safe to initialize this only once
98
for ( f = FILESYSTEM_MAP .begin() ; f != FILESYSTEM_MAP .end() ; f++ ) {
103
FILESYSTEM_MAP .clear() ;
105
FILESYSTEM_MAP[ FS_BTRFS ] = new btrfs() ;
106
FILESYSTEM_MAP[ FS_EXFAT ] = new exfat() ;
107
FILESYSTEM_MAP[ FS_EXT2 ] = new ext2() ;
108
FILESYSTEM_MAP[ FS_EXT3 ] = new ext3() ;
109
FILESYSTEM_MAP[ FS_EXT4 ] = new ext4() ;
110
FILESYSTEM_MAP[ FS_FAT16 ] = new fat16() ;
111
FILESYSTEM_MAP[ FS_FAT32 ] = new fat32() ;
112
FILESYSTEM_MAP[ FS_HFS ] = new hfs() ;
113
FILESYSTEM_MAP[ FS_HFSPLUS ] = new hfsplus() ;
114
FILESYSTEM_MAP[ FS_JFS ] = new jfs() ;
115
FILESYSTEM_MAP[ FS_LINUX_SWAP ] = new linux_swap() ;
116
FILESYSTEM_MAP[ FS_LVM2_PV ] = new lvm2_pv() ;
117
FILESYSTEM_MAP[ FS_NILFS2 ] = new nilfs2() ;
118
FILESYSTEM_MAP[ FS_NTFS ] = new ntfs() ;
119
FILESYSTEM_MAP[ FS_REISER4 ] = new reiser4() ;
120
FILESYSTEM_MAP[ FS_REISERFS ] = new reiserfs() ;
121
FILESYSTEM_MAP[ FS_UFS ] = new ufs() ;
122
FILESYSTEM_MAP[ FS_XFS ] = new xfs() ;
123
FILESYSTEM_MAP[ FS_LUKS ] = NULL ;
124
FILESYSTEM_MAP[ FS_UNKNOWN ] = NULL ;
126
FILESYSTEMS .clear() ;
129
for ( f = FILESYSTEM_MAP .begin() ; f != FILESYSTEM_MAP .end() ; f++ ) {
131
FILESYSTEMS .push_back( f ->second ->get_filesystem_support() ) ;
133
fs_notsupp .filesystem = f ->first ;
134
FILESYSTEMS .push_back( fs_notsupp ) ;
139
void GParted_Core::set_user_devices( const std::vector<Glib::ustring> & user_devices )
141
this ->device_paths = user_devices ;
142
this ->probe_devices = ! user_devices .size() ;
145
void GParted_Core::set_devices( std::vector<Device> & devices )
149
Proc_Partitions_Info pp_info( true ) ; //Refresh cache of proc partition information
150
FS_Info fs_info( true ) ; //Refresh cache of file system information
151
DMRaid dmraid( true ) ; //Refresh cache of dmraid device information
152
SWRaid swraid( true ) ; //Refresh cache of swraid device information
153
LVM2_PV_Info lvm2_pv_info( true ) ; //Refresh cache of LVM2 PV information
157
//only probe if no devices were specified as arguments..
160
device_paths .clear() ;
162
//FIXME: When libparted bug 194 is fixed, remove code to read:
164
// This was a problem with no floppy drive yet BIOS indicated one existed.
165
// http://parted.alioth.debian.org/cgi-bin/trac.cgi/ticket/194
167
//try to find all available devices if devices exist in /proc/partitions
168
std::vector<Glib::ustring> temp_devices = pp_info .get_device_paths() ;
169
if ( ! temp_devices .empty() )
171
//Try to find all devices in /proc/partitions
172
for (unsigned int k=0; k < temp_devices .size(); k++)
174
/*TO TRANSLATORS: looks like Scanning /dev/sda */
175
set_thread_status_message( String::ucompose ( _("Scanning %1"), temp_devices[ k ] ) ) ;
176
ped_device_get( temp_devices[ k ] .c_str() ) ;
179
//Try to find all swraid devices
180
if (swraid .is_swraid_supported() ) {
181
std::vector<Glib::ustring> swraid_devices ;
182
swraid .get_devices( swraid_devices ) ;
183
for ( unsigned int k=0; k < swraid_devices .size(); k++ ) {
184
set_thread_status_message( String::ucompose ( _("Scanning %1"), swraid_devices[k] ) ) ;
185
ped_device_get( swraid_devices[k] .c_str() ) ;
189
//Try to find all dmraid devices
190
if (dmraid .is_dmraid_supported() ) {
191
std::vector<Glib::ustring> dmraid_devices ;
192
dmraid .get_devices( dmraid_devices ) ;
193
for ( unsigned int k=0; k < dmraid_devices .size(); k++ ) {
194
set_thread_status_message( String::ucompose ( _("Scanning %1"), dmraid_devices[k] ) ) ;
195
#ifndef USE_LIBPARTED_DMRAID
196
dmraid .create_dev_map_entries( dmraid_devices[k] ) ;
199
ped_device_get( dmraid_devices[k] .c_str() ) ;
205
//No devices found in /proc/partitions so use libparted to probe devices
206
ped_device_probe_all();
209
lp_device = ped_device_get_next( NULL );
212
//only add this device if we can read the first sector (which means it's a real device)
213
char * buf = static_cast<char *>( malloc( lp_device ->sector_size ) ) ;
216
/*TO TRANSLATORS: looks like Confirming /dev/sda */
217
set_thread_status_message( String::ucompose ( _("Confirming %1"), lp_device ->path ) ) ;
218
if ( ped_device_open( lp_device ) )
220
#ifdef HAVE_LIBPARTED_2_2_0_PLUS
221
//Devices with sector sizes of 512 bytes and higher are supported
222
if ( ped_device_read( lp_device, buf, 0, 1 ) )
223
device_paths .push_back( lp_device ->path ) ;
225
//Only devices with sector sizes of 512 bytes are well supported
226
if ( lp_device ->sector_size != 512 )
228
/*TO TRANSLATORS: looks like Ignoring device /dev/sde with logical sector size of 2048 bytes. */
229
Glib::ustring msg = String::ucompose ( _("Ignoring device %1 with logical sector size of %2 bytes."), lp_device ->path, lp_device ->sector_size ) ;
231
msg += _("GParted requires libparted version 2.2 or higher to support devices with sector sizes larger than 512 bytes.") ;
232
std::cout << msg << std::endl << std::endl ;
236
if ( ped_device_read( lp_device, buf, 0, 1 ) )
237
device_paths .push_back( lp_device ->path ) ;
240
ped_device_close( lp_device ) ;
244
lp_device = ped_device_get_next( lp_device ) ;
246
close_device_and_disk() ;
248
std::sort( device_paths .begin(), device_paths .end() ) ;
250
#ifndef USE_LIBPARTED_DMRAID
253
//Device paths were passed in on the command line.
255
//Ensure that dmraid device entries are created
256
for ( unsigned int t = 0 ; t < device_paths .size() ; t++ )
258
if ( dmraid .is_dmraid_supported() &&
259
dmraid .is_dmraid_device( device_paths[t] ) )
261
dmraid .create_dev_map_entries( dmraid .get_dmraid_name( device_paths [t] ) ) ;
267
for ( unsigned int t = 0 ; t < device_paths .size() ; t++ )
269
/*TO TRANSLATORS: looks like Searching /dev/sda partitions */
270
set_thread_status_message( String::ucompose ( _("Searching %1 partitions"), device_paths[ t ] ) ) ;
271
if ( open_device_and_disk( device_paths[ t ], false ) )
273
temp_device .Reset() ;
276
temp_device .add_path( device_paths[ t ] ) ;
277
temp_device .add_paths( pp_info .get_alternate_paths( temp_device .get_path() ) ) ;
279
temp_device .model = lp_device ->model ;
280
temp_device .length = lp_device ->length ;
281
temp_device .sector_size = lp_device ->sector_size ;
282
temp_device .heads = lp_device ->bios_geom .heads ;
283
temp_device .sectors = lp_device ->bios_geom .sectors ;
284
temp_device .cylinders = lp_device ->bios_geom .cylinders ;
285
temp_device .cylsize = temp_device .heads * temp_device .sectors ;
287
//make sure cylsize is at least 1 MiB
288
if ( temp_device .cylsize < (MEBIBYTE / temp_device .sector_size) )
289
temp_device .cylsize = (MEBIBYTE / temp_device .sector_size) ;
294
temp_device .disktype = lp_disk ->type ->name ;
295
temp_device .max_prims = ped_disk_get_max_primary_partition_count( lp_disk ) ;
297
set_device_partitions( temp_device ) ;
298
set_mountpoints( temp_device .partitions ) ;
299
set_used_sectors( temp_device .partitions ) ;
301
if ( temp_device .highest_busy )
303
temp_device .readonly = ! commit_to_os( 1 ) ;
304
//Clear libparted messages. Typically these are:
305
// The kernel was unable to re-read the partition table...
306
libparted_messages .clear() ;
309
//harddisk without disklabel
312
temp_device .disktype =
313
/* TO TRANSLATORS: unrecognized
314
* means that the partition table for this
315
* disk device is unknown or not recognized.
318
temp_device .max_prims = -1 ;
320
Partition partition_temp ;
321
partition_temp .Set_Unallocated( temp_device .get_path(),
323
temp_device .length - 1,
324
temp_device .sector_size,
326
//Place libparted messages in this unallocated partition
327
partition_temp .messages .insert( partition_temp .messages .end(),
328
libparted_messages. begin(),
329
libparted_messages .end() ) ;
330
libparted_messages .clear() ;
331
temp_device .partitions .push_back( partition_temp );
334
devices .push_back( temp_device ) ;
336
close_device_and_disk() ;
340
//clear leftover information...
341
//NOTE that we cannot clear mountinfo since it might be needed in get_all_mountpoints()
342
set_thread_status_message("") ;
343
fstab_info .clear() ;
346
// runs gpart on the specified parameter
347
void GParted_Core::guess_partition_table(const Device & device, Glib::ustring &buff)
349
int pid, stdoutput, stderror;
350
std::vector<std::string> argvproc, envpproc;
353
//Get the char string of the sector_size
354
std::ostringstream ssIn;
355
ssIn << device.sector_size;
356
Glib::ustring str_ssize = ssIn.str();
358
//Build the command line
359
argvproc.push_back("gpart");
360
argvproc.push_back(device.get_path());
361
argvproc.push_back("-s");
362
argvproc.push_back(str_ssize);
364
envpproc .push_back( "LC_ALL=C" ) ;
365
envpproc .push_back( "PATH=" + Glib::getenv( "PATH" ) ) ;
367
Glib::spawn_async_with_pipes(Glib::get_current_dir(), argvproc,
368
envpproc, Glib::SPAWN_SEARCH_PATH, sigc::slot<void>(),
369
&pid, NULL, &stdoutput, &stderror);
371
this->iocOutput=Glib::IOChannel::create_from_fd(stdoutput);
373
while(this->iocOutput->read(tmp)==Glib::IO_STATUS_NORMAL)
377
this->iocOutput->close();
382
void GParted_Core::set_thread_status_message( Glib::ustring msg )
384
//Remember to clear status message when finished with thread.
385
thread_status_message = msg ;
388
Glib::ustring GParted_Core::get_thread_status_message( )
390
return thread_status_message ;
393
bool GParted_Core::snap_to_cylinder( const Device & device, Partition & partition, Glib::ustring & error )
397
//Determine if partition size is less than half a disk cylinder
398
bool less_than_half_cylinder = false;
399
if ( ( partition .sector_end - partition .sector_start ) < ( device .cylsize / 2 ) )
400
less_than_half_cylinder = true;
402
if ( partition.type == TYPE_LOGICAL ||
403
partition.sector_start == device .sectors
406
//Must account the relative offset between:
407
// (A) the Extended Boot Record sector and the next track of the
408
// logical partition (usually 63 sectors), and
409
// (B) the Master Boot Record sector and the next track of the first
411
diff = (partition .sector_start - device .sectors) % device .cylsize ;
413
else if ( partition.sector_start == 34 )
415
// (C) the GUID Partition Table (GPT) and the start of the data
416
// partition at sector 34
417
diff = (partition .sector_start - 34 ) % device .cylsize ;
421
diff = partition .sector_start % device .cylsize ;
423
if ( diff && ! partition .strict_start )
425
if ( diff < ( device .cylsize / 2 ) || less_than_half_cylinder )
426
partition .sector_start -= diff ;
428
partition .sector_start += (device .cylsize - diff ) ;
431
diff = (partition .sector_end +1) % device .cylsize ;
434
if ( diff < ( device .cylsize / 2 ) && ! less_than_half_cylinder )
435
partition .sector_end -= diff ;
437
partition .sector_end += (device .cylsize - diff ) ;
443
bool GParted_Core::snap_to_mebibyte( const Device & device, Partition & partition, Glib::ustring & error )
446
if ( partition .sector_start < 2 || partition .type == TYPE_LOGICAL )
448
//Must account the relative offset between:
449
// (A) the Master Boot Record sector and the first primary/extended partition, and
450
// (B) the Extended Boot Record sector and the logical partition
452
//If strict_start is set then do not adjust sector start.
453
//If this partition is not simply queued for a reformat then
454
// add space minimum to force alignment to next mebibyte.
455
if ( (! partition .strict_start)
456
&& (partition .free_space_before == 0)
457
&& ( partition .status != STAT_FORMATTED)
460
//Unless specifically told otherwise, the Linux kernel considers extended
461
// boot records to be two sectors long, in order to "leave room for LILO".
462
partition .sector_start += 2 ;
466
//Calculate difference offset from Mebibyte boundary
467
diff = Sector(partition .sector_start % ( MEBIBYTE / partition .sector_size ));
469
//Align start sector only if permitted to change start sector
470
if ( diff && ( (! partition .strict_start)
471
|| ( partition .strict_start
472
&& ( partition .status == STAT_NEW
473
|| partition .status == STAT_COPY
479
partition .sector_start += ( (MEBIBYTE / partition .sector_size) - diff) ;
481
//If this is an extended partition then check to see if sufficient space is
482
// available for any following logical partition Extended Boot Record
483
if ( partition .type == TYPE_EXTENDED )
485
//Locate the extended partition that contains the logical partitions.
486
int index_extended = -1 ;
487
for ( unsigned int t = 0 ; t < device .partitions .size() ; t++ )
489
if ( device .partitions[ t ] .type == TYPE_EXTENDED )
493
//If there is logical partition that starts less than 2 sectors
494
// from the start of this partition, then reserve a mebibyte for the EBR.
495
if ( index_extended != -1 )
497
for ( unsigned int t = 0; t < device .partitions[ index_extended ] .logicals .size(); t++ )
499
if ( ( device .partitions[ index_extended ] .logicals[ t ] .type == TYPE_LOGICAL )
500
&& ( ( ( device .partitions[ index_extended ] .logicals[ t ] .sector_start )
501
- ( partition .sector_start )
503
//Unless specifically told otherwise, the Linux kernel considers extended
504
// boot records to be two sectors long, in order to "leave room for LILO".
509
partition .sector_start -= (MEBIBYTE / partition .sector_size) ;
517
diff = (partition .sector_end + 1) % ( MEBIBYTE / partition .sector_size);
519
partition .sector_end -= diff ;
521
//If this is a logical partition not at end of drive then check to see if space is
522
// required for a following logical partition Extended Boot Record
523
if ( partition .type == TYPE_LOGICAL )
525
//Locate the extended partition that contains the logical partitions.
526
int index_extended = -1 ;
527
for ( unsigned int t = 0 ; t < device .partitions .size() ; t++ )
529
if ( device .partitions[ t ] .type == TYPE_EXTENDED )
533
//If there is a following logical partition that starts less than 2 sectors from
534
// the end of this partition, then reserve at least a mebibyte for the EBR.
535
if ( index_extended != -1 )
537
for ( unsigned int t = 0; t < device .partitions[ index_extended ] .logicals .size(); t++ )
539
if ( ( device .partitions[ index_extended ] .logicals[ t ] .type == TYPE_LOGICAL )
540
&& ( device .partitions[ index_extended ] .logicals[ t ] .sector_start > partition .sector_end )
541
&& ( ( device .partitions[ index_extended ] .logicals[ t ] .sector_start - partition .sector_end )
542
//Unless specifically told otherwise, the Linux kernel considers extended
543
// boot records to be two sectors long, in order to "leave room for LILO".
547
partition .sector_end -= ( MEBIBYTE / partition .sector_size ) ;
552
//If this is a primary or an extended partition and the partition overlaps
553
// the start of the next primary or extended partition then subtract a
554
// mebibyte from the end of the partition to address the overlap.
555
if ( partition .type == TYPE_PRIMARY || partition .type == TYPE_EXTENDED )
557
for ( unsigned int t = 0 ; t < device .partitions .size() ; t++ )
559
if ( ( device .partitions[ t ] .type == TYPE_PRIMARY
560
|| device .partitions[ t ] .type == TYPE_EXTENDED
562
&& ( device .partitions[ t ] .sector_start > partition .sector_start )
563
&& ( device .partitions[ t ] .sector_start <= partition .sector_end )
565
partition .sector_end -= ( MEBIBYTE / partition .sector_size );
569
//If this is a GPT partition table and the partition ends less than 34 sectors
570
// from the end of the device, then reserve at least a mebibyte for the
571
// backup partition table
572
if ( device .disktype == "gpt"
573
&& ( ( device .length - partition .sector_end ) < 34 )
576
partition .sector_end -= ( MEBIBYTE / partition .sector_size ) ;
582
bool GParted_Core::snap_to_alignment( const Device & device, Partition & partition, Glib::ustring & error )
586
if ( partition .alignment == ALIGN_CYLINDER )
587
rc = snap_to_cylinder( device, partition, error ) ;
588
else if ( partition .alignment == ALIGN_MEBIBYTE )
589
rc = snap_to_mebibyte( device, partition, error ) ;
591
//Ensure that partition start and end are not beyond the ends of the disk device
592
if ( partition .sector_start < 0 )
593
partition .sector_start = 0 ;
594
if ( partition .sector_end > device .length )
595
partition .sector_end = device .length - 1 ;
597
//do some basic checks on the partition
598
if ( partition .get_sector_length() <= 0 )
600
error = String::ucompose(
601
/* TO TRANSLATORS: looks like A partition cannot have a length of -1 sectors */
602
_("A partition cannot have a length of %1 sectors"),
603
partition .get_sector_length() ) ;
607
if ( partition .get_sector_length() < partition .sectors_used )
609
error = String::ucompose(
610
/* TO TRANSLATORS: looks like A partition with used sectors (2048) greater than its length (1536) is not valid */
611
_("A partition with used sectors (%1) greater than its length (%2) is not valid"),
612
partition .sectors_used,
613
partition .get_sector_length() ) ;
617
//FIXME: it would be perfect if we could check for overlapping with adjacent partitions as well,
618
//however, finding the adjacent partitions is not as easy as it seems and at this moment all the dialogs
619
//already perform these checks. A perfect 'fixme-later' ;)
624
bool GParted_Core::apply_operation_to_disk( Operation * operation )
626
bool succes = false ;
627
libparted_messages .clear() ;
629
if ( calibrate_partition( operation ->partition_original, operation ->operation_detail ) )
630
switch ( operation ->type )
632
case OPERATION_DELETE:
633
succes = Delete( operation ->partition_original, operation ->operation_detail ) ;
635
case OPERATION_CHECK:
636
succes = check_repair_filesystem( operation ->partition_original, operation ->operation_detail ) &&
637
maximize_filesystem( operation ->partition_original, operation ->operation_detail ) ;
639
case OPERATION_CREATE:
640
succes = create( operation ->device,
641
operation ->partition_new,
642
operation ->operation_detail ) ;
644
case OPERATION_RESIZE_MOVE:
645
//in case the to be resized/moved partition was a 'copy of..', we need a real path...
646
operation ->partition_new .add_path( operation ->partition_original .get_path(), true ) ;
647
succes = resize_move( operation ->device,
648
operation ->partition_original,
649
operation ->partition_new,
650
operation ->operation_detail ) ;
652
case OPERATION_FORMAT:
653
succes = format( operation ->partition_new, operation ->operation_detail ) ;
656
//FIXME: in case of a new partition we should make sure the new partition is >= the source partition...
657
//i think it's best to do this in the dialog_paste
658
succes = ( operation ->partition_original .type == TYPE_UNALLOCATED ||
659
calibrate_partition( operation ->partition_new, operation ->operation_detail ) ) &&
661
calibrate_partition( static_cast<OperationCopy*>( operation ) ->partition_copied,
662
operation ->operation_detail ) &&
664
copy( static_cast<OperationCopy*>( operation ) ->partition_copied,
665
operation ->partition_new,
666
static_cast<OperationCopy*>( operation ) ->partition_copied .get_byte_length(),
667
operation ->operation_detail ) ;
669
case OPERATION_LABEL_PARTITION:
670
succes = label_partition( operation ->partition_new, operation ->operation_detail ) ;
672
case OPERATION_CHANGE_UUID:
673
succes = change_uuid( operation ->partition_new, operation ->operation_detail ) ;
677
if ( libparted_messages .size() > 0 )
679
operation ->operation_detail .add_child( OperationDetail( _("libparted messages"), STATUS_INFO ) ) ;
681
for ( unsigned int t = 0 ; t < libparted_messages .size() ; t++ )
682
operation ->operation_detail .get_last_child() .add_child(
683
OperationDetail( libparted_messages[ t ], STATUS_NONE, FONT_ITALIC ) ) ;
689
bool GParted_Core::set_disklabel( const Glib::ustring & device_path, const Glib::ustring & disklabel )
691
bool return_value = false ;
693
if ( open_device_and_disk( device_path, false ) )
695
PedDiskType *type = NULL ;
696
type = ped_disk_type_get( disklabel .c_str() ) ;
700
lp_disk = ped_disk_new_fresh( lp_device, type );
702
return_value = commit() ;
705
close_device_and_disk() ;
708
#ifndef USE_LIBPARTED_DMRAID
709
//delete and recreate disk entries if dmraid
711
if ( return_value && dmraid .is_dmraid_device( device_path ) )
713
dmraid .purge_dev_map_entries( device_path ) ;
714
dmraid .create_dev_map_entries( device_path ) ;
718
return return_value ;
721
bool GParted_Core::toggle_flag( const Partition & partition, const Glib::ustring & flag, bool state )
723
bool succes = false ;
725
if ( open_device_and_disk( partition .device_path ) )
727
lp_partition = NULL ;
728
if ( partition .type == GParted::TYPE_EXTENDED )
729
lp_partition = ped_disk_extended_partition( lp_disk ) ;
731
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
735
PedPartitionFlag lp_flag = ped_partition_flag_get_by_name( flag .c_str() ) ;
737
if ( lp_flag > 0 && ped_partition_set_flag( lp_partition, lp_flag, state ) )
741
close_device_and_disk() ;
747
const std::vector<FS> & GParted_Core::get_filesystems() const
752
const FS & GParted_Core::get_fs( GParted::FILESYSTEM filesystem ) const
754
unsigned int unknown ;
756
unknown = FILESYSTEMS .size() ;
757
for ( unsigned int t = 0 ; t < FILESYSTEMS .size() ; t++ )
759
if ( FILESYSTEMS[ t ] .filesystem == filesystem )
760
return FILESYSTEMS[ t ] ;
761
else if ( FILESYSTEMS[ t ] .filesystem == FS_UNKNOWN )
765
if ( unknown == FILESYSTEMS .size() ) {
766
// This shouldn't happen, but just in case...
768
fs .filesystem = FS_UNKNOWN ;
771
return FILESYSTEMS[ unknown ] ;
774
std::vector<Glib::ustring> GParted_Core::get_disklabeltypes()
776
std::vector<Glib::ustring> disklabeltypes ;
778
//msdos should be first in the list
779
disklabeltypes .push_back( "msdos" ) ;
781
PedDiskType *disk_type ;
782
for ( disk_type = ped_disk_type_get_next( NULL ) ; disk_type ; disk_type = ped_disk_type_get_next( disk_type ) )
783
if ( Glib::ustring( disk_type->name ) != "msdos" )
784
disklabeltypes .push_back( disk_type->name ) ;
786
return disklabeltypes ;
789
std::vector<Glib::ustring> GParted_Core::get_all_mountpoints()
791
std::vector<Glib::ustring> mountpoints ;
793
for ( iter_mp = mount_info .begin() ; iter_mp != mount_info .end() ; ++iter_mp )
794
mountpoints .insert( mountpoints .end(), iter_mp ->second .begin(), iter_mp ->second .end() ) ;
799
std::map<Glib::ustring, bool> GParted_Core::get_available_flags( const Partition & partition )
801
std::map<Glib::ustring, bool> flag_info ;
803
if ( open_device_and_disk( partition .device_path ) )
805
lp_partition = NULL ;
806
if ( partition .type == GParted::TYPE_EXTENDED )
807
lp_partition = ped_disk_extended_partition( lp_disk ) ;
809
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
813
for ( unsigned int t = 0 ; t < flags .size() ; t++ )
814
if ( ped_partition_is_flag_available( lp_partition, flags[ t ] ) )
815
flag_info[ ped_partition_flag_get_name( flags[ t ] ) ] =
816
ped_partition_get_flag( lp_partition, flags[ t ] ) ;
819
close_device_and_disk() ;
825
Glib::ustring GParted_Core::get_libparted_version()
827
return ped_get_version() ;
830
//private functions...
832
void GParted_Core::init_maps()
834
mount_info .clear() ;
835
fstab_info .clear() ;
837
read_mountpoints_from_file( "/proc/mounts", mount_info ) ;
838
read_mountpoints_from_file_swaps( "/proc/swaps", mount_info ) ;
839
read_mountpoints_from_file( "/etc/mtab", mount_info ) ;
840
read_mountpoints_from_file( "/etc/fstab", fstab_info ) ;
842
//sort the mount points and remove duplicates.. (no need to do this for fstab_info)
843
for ( iter_mp = mount_info .begin() ; iter_mp != mount_info .end() ; ++iter_mp )
845
std::sort( iter_mp ->second .begin(), iter_mp ->second .end() ) ;
847
iter_mp ->second .erase(
848
std::unique( iter_mp ->second .begin(), iter_mp ->second .end() ),
849
iter_mp ->second .end() ) ;
853
void GParted_Core::read_mountpoints_from_file(
854
const Glib::ustring & filename,
855
std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
857
FS_Info fs_info ; //Use cache of file system information
859
FILE* fp = setmntent( filename .c_str(), "r" ) ;
864
struct mntent* p = NULL ;
866
while ( (p = getmntent(fp)) != NULL )
868
Glib::ustring node = p->mnt_fsname ;
870
Glib::ustring uuid = Utils::regexp_label( node, "^UUID=(.*)" ) ;
871
if ( ! uuid .empty() )
872
node = fs_info .get_path_by_uuid( uuid ) ;
874
Glib::ustring label = Utils::regexp_label( node, "^LABEL=(.*)" ) ;
875
if ( ! label .empty() )
876
node = fs_info .get_path_by_label( label ) ;
878
if ( ! node .empty() )
880
Glib::ustring mountpoint = p->mnt_dir ;
882
//Only add node path(s) if mount point exists
883
if ( file_test( mountpoint, Glib::FILE_TEST_EXISTS ) )
885
map[ node ] .push_back( mountpoint ) ;
887
//If node is a symbolic link (e.g., /dev/root)
888
// then find real path and add entry
889
if ( file_test( node, Glib::FILE_TEST_IS_SYMLINK ) )
892
//FIXME: it seems realpath is very unsafe to use (manpage)...
893
if ( realpath( node .c_str(), c_str ) != NULL )
894
map[ c_str ] .push_back( mountpoint ) ;
903
void GParted_Core::read_mountpoints_from_file_swaps(
904
const Glib::ustring & filename,
905
std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
910
std::ifstream file( filename .c_str() ) ;
913
while ( getline( file, line ) )
915
node = Utils::regexp_label( line, "^(/[^ ]+)" ) ;
916
if ( node .size() > 0 )
917
map[ node ] .push_back( "" /* no mountpoint for swap */ ) ;
923
Glib::ustring GParted_Core::get_partition_path( PedPartition * lp_partition )
925
char * lp_path; //we have to free the result of ped_partition_get_path()
926
Glib::ustring partition_path = "Partition path not found";
928
lp_path = ped_partition_get_path(lp_partition);
929
if ( lp_path != NULL )
931
partition_path = lp_path;
935
#ifndef USE_LIBPARTED_DMRAID
936
//Ensure partition path name is compatible with dmraid
937
DMRaid dmraid; //Use cache of dmraid device information
938
if ( dmraid .is_dmraid_supported()
939
&& dmraid .is_dmraid_device( partition_path )
942
partition_path = dmraid .make_path_dmraid_compatible(partition_path);
946
return partition_path ;
949
void GParted_Core::set_device_partitions( Device & device )
952
Proc_Partitions_Info pp_info ; //Use cache of proc partitions information
953
FS_Info fs_info ; //Use cache of file system information
954
#ifndef USE_LIBPARTED_DMRAID
955
DMRaid dmraid ; //Use cache of dmraid device information
957
LVM2_PV_Info lvm2_pv_info ;
960
device .partitions .clear() ;
962
lp_partition = ped_disk_next_partition( lp_disk, NULL ) ;
963
while ( lp_partition )
965
libparted_messages .clear() ;
966
partition_temp .Reset() ;
967
bool partition_is_busy = false ;
968
GParted::FILESYSTEM filesystem ;
970
//Retrieve partition path
971
Glib::ustring partition_path = get_partition_path( lp_partition );
973
switch ( lp_partition ->type )
975
case PED_PARTITION_NORMAL:
976
case PED_PARTITION_LOGICAL:
977
filesystem = get_filesystem() ;
978
#ifndef USE_LIBPARTED_DMRAID
979
//Handle dmraid devices differently because the minor number might not
980
// match the last number of the partition filename as shown by "ls -l /dev/mapper"
981
// This mismatch causes incorrect identification of busy partitions in ped_partition_is_busy().
982
if ( dmraid .is_dmraid_device( device .get_path() ) )
984
//Try device_name + partition_number
985
iter_mp = mount_info .find( device .get_path() + Utils::num_to_str( lp_partition ->num ) ) ;
986
if ( iter_mp != mount_info .end() )
987
partition_is_busy = true ;
988
//Try device_name + p + partition_number
989
iter_mp = mount_info .find( device .get_path() + "p" + Utils::num_to_str( lp_partition ->num ) ) ;
990
if ( iter_mp != mount_info .end() )
991
partition_is_busy = true ;
995
partition_is_busy = ped_partition_is_busy( lp_partition ) ||
996
( filesystem == GParted::FS_LVM2_PV && lvm2_pv_info .has_active_lvs( partition_path ) ) ;
998
partition_temp .Set( device .get_path(),
1001
lp_partition ->type == 0 ? GParted::TYPE_PRIMARY : GParted::TYPE_LOGICAL,
1003
lp_partition ->geom .start,
1004
lp_partition ->geom .end,
1005
device .sector_size,
1006
lp_partition ->type,
1007
partition_is_busy ) ;
1009
partition_temp .add_paths( pp_info .get_alternate_paths( partition_temp .get_path() ) ) ;
1010
set_flags( partition_temp ) ;
1012
if ( partition_temp .busy && partition_temp .partition_number > device .highest_busy )
1013
device .highest_busy = partition_temp .partition_number ;
1017
case PED_PARTITION_EXTENDED:
1018
#ifndef USE_LIBPARTED_DMRAID
1019
//Handle dmraid devices differently because the minor number might not
1020
// match the last number of the partition filename as shown by "ls -l /dev/mapper"
1021
// This mismatch causes incorrect identification of busy partitions in ped_partition_is_busy().
1022
if ( dmraid .is_dmraid_device( device .get_path() ) )
1024
for ( unsigned int k = 5; k < 255; k++ )
1026
//Try device_name + [5 to 255]
1027
iter_mp = mount_info .find( device .get_path() + Utils::num_to_str( k ) ) ;
1028
if ( iter_mp != mount_info .end() )
1029
partition_is_busy = true ;
1030
//Try device_name + p + [5 to 255]
1031
iter_mp = mount_info .find( device .get_path() + "p" + Utils::num_to_str( k ) ) ;
1032
if ( iter_mp != mount_info .end() )
1033
partition_is_busy = true ;
1038
partition_is_busy = ped_partition_is_busy( lp_partition ) ;
1040
partition_temp .Set( device .get_path(),
1043
GParted::TYPE_EXTENDED,
1044
GParted::FS_EXTENDED,
1045
lp_partition ->geom .start,
1046
lp_partition ->geom .end,
1047
device .sector_size,
1049
partition_is_busy ) ;
1051
partition_temp .add_paths( pp_info .get_alternate_paths( partition_temp .get_path() ) ) ;
1052
set_flags( partition_temp ) ;
1054
EXT_INDEX = device .partitions .size() ;
1061
//Avoid reading additional file system information if there is no path
1062
if ( partition_temp .get_path() != "" )
1064
//Retrieve file system label
1065
// Use file system specific method first in an effort to ensure multi-byte
1066
// character sets are properly displayed.
1067
read_label( partition_temp ) ;
1068
if ( partition_temp .label .empty() )
1070
bool label_found = false ;
1071
partition_temp .label = fs_info .get_label( partition_temp .get_path(), label_found ) ;
1074
//Retrieve file system UUID
1075
// Use cached method first in an effort to speed up device scanning.
1076
partition_temp .uuid = fs_info .get_uuid( partition_temp .get_path() ) ;
1077
if ( partition_temp .uuid .empty() )
1079
read_uuid( partition_temp ) ;
1083
partition_temp .messages .insert( partition_temp .messages .end(),
1084
libparted_messages. begin(),
1085
libparted_messages .end() ) ;
1087
//if there's an end, there's a partition ;)
1088
if ( partition_temp .sector_end > -1 )
1090
if ( ! partition_temp .inside_extended )
1091
device .partitions .push_back( partition_temp );
1093
device .partitions[ EXT_INDEX ] .logicals .push_back( partition_temp ) ;
1096
//next partition (if any)
1097
lp_partition = ped_disk_next_partition( lp_disk, lp_partition ) ;
1100
if ( EXT_INDEX > -1 )
1101
insert_unallocated( device .get_path(),
1102
device .partitions[ EXT_INDEX ] .logicals,
1103
device .partitions[ EXT_INDEX ] .sector_start,
1104
device .partitions[ EXT_INDEX ] .sector_end,
1105
device .sector_size,
1108
insert_unallocated( device .get_path(), device .partitions, 0, device .length -1, device .sector_size, false ) ;
1111
GParted::FILESYSTEM GParted_Core::get_filesystem()
1113
char magic1[16] = "";
1114
char magic2[16] = "";
1116
//Check for LUKS encryption prior to libparted file system detection.
1117
// Otherwise encrypted file systems such as ext3 will be detected by
1118
// libparted as 'ext3'.
1121
char * buf = static_cast<char *>( malloc( lp_device ->sector_size ) ) ;
1124
ped_device_open( lp_device );
1125
ped_geometry_read( & lp_partition ->geom, buf, 0, 1 ) ;
1126
memcpy(magic1, buf+0, 6) ; //set binary magic data
1127
ped_device_close( lp_device );
1130
if ( 0 == memcmp( magic1 , "LUKS\xBA\xBE", 6 ) )
1132
temp = _( "Linux Unified Key Setup encryption is not yet supported." ) ;
1134
partition_temp .messages .push_back( temp ) ;
1135
return GParted::FS_LUKS ;
1140
Glib::ustring fs_type = "" ;
1142
//Standard libparted file system detection
1143
if ( lp_partition && lp_partition ->fs_type )
1145
fs_type = lp_partition ->fs_type ->name ;
1147
//TODO: Temporary code to detect ext4.
1148
// Replace when libparted >= 1.9.0 is chosen as minimum required version.
1149
temp = fs_info .get_fs_type( get_partition_path( lp_partition ) ) ;
1150
if ( temp == "ext4" || temp == "ext4dev" )
1154
//FS_Info (blkid) file system detection because current libparted (v2.2) does not
1155
// appear to detect file systems for sector sizes other than 512 bytes.
1156
if ( fs_type .empty() )
1158
//TODO: blkid does not return anything for an "extended" partition. Need to handle this somehow
1159
fs_type = fs_info.get_fs_type( get_partition_path( lp_partition ) ) ;
1162
if ( ! fs_type .empty() )
1164
if ( fs_type == "extended" )
1165
return GParted::FS_EXTENDED ;
1166
else if ( fs_type == "btrfs" )
1167
return GParted::FS_BTRFS ;
1168
else if ( fs_type == "exfat" )
1169
return GParted::FS_EXFAT ;
1170
else if ( fs_type == "ext2" )
1171
return GParted::FS_EXT2 ;
1172
else if ( fs_type == "ext3" )
1173
return GParted::FS_EXT3 ;
1174
else if ( fs_type == "ext4" ||
1175
fs_type == "ext4dev" )
1176
return GParted::FS_EXT4 ;
1177
else if ( fs_type == "linux-swap" ||
1178
fs_type == "linux-swap(v1)" ||
1179
fs_type == "linux-swap(new)" ||
1180
fs_type == "linux-swap(v0)" ||
1181
fs_type == "linux-swap(old)" ||
1183
return GParted::FS_LINUX_SWAP ;
1184
else if ( fs_type == "LVM2_member" )
1185
return GParted::FS_LVM2_PV ;
1186
else if ( fs_type == "fat16" )
1187
return GParted::FS_FAT16 ;
1188
else if ( fs_type == "fat32" )
1189
return GParted::FS_FAT32 ;
1190
else if ( fs_type == "nilfs2" )
1191
return GParted::FS_NILFS2 ;
1192
else if ( fs_type == "ntfs" )
1193
return GParted::FS_NTFS ;
1194
else if ( fs_type == "reiserfs" )
1195
return GParted::FS_REISERFS ;
1196
else if ( fs_type == "xfs" )
1197
return GParted::FS_XFS ;
1198
else if ( fs_type == "jfs" )
1199
return GParted::FS_JFS ;
1200
else if ( fs_type == "hfs" )
1201
return GParted::FS_HFS ;
1202
else if ( fs_type == "hfs+" ||
1203
fs_type == "hfsplus" )
1204
return GParted::FS_HFSPLUS ;
1205
else if ( fs_type == "ufs" )
1206
return GParted::FS_UFS ;
1211
//other file systems libparted couldn't detect (i've send patches for these file systems to the parted guys)
1212
// - no patches sent to parted for lvm2, or luks
1215
buf = static_cast<char *>( malloc( lp_device ->sector_size ) ) ;
1218
ped_device_open( lp_device );
1219
ped_geometry_read( & lp_partition ->geom
1221
, (65536 / lp_device ->sector_size)
1224
memcpy(magic1, buf+0, 7) ; //set binary magic data
1225
ped_device_close( lp_device );
1228
if ( 0 == memcmp( magic1, "ReIsEr4", 7 ) )
1229
return GParted::FS_REISER4 ;
1233
//NOTE: lvm2 is not a file system but we do wish to recognize the Physical Volume
1234
buf = static_cast<char *>( malloc( lp_device ->sector_size ) ) ;
1237
ped_device_open( lp_device );
1238
if ( lp_device ->sector_size == 512 )
1240
ped_geometry_read( & lp_partition ->geom, buf, 1, 1 ) ;
1241
memcpy(magic1, buf+ 0, 8) ; // set binary magic data
1242
memcpy(magic2, buf+24, 4) ; // set binary magic data
1246
ped_geometry_read( & lp_partition ->geom, buf, 0, 1 ) ;
1247
memcpy(magic1, buf+ 0+512, 8) ; // set binary magic data
1248
memcpy(magic2, buf+24+512, 4) ; // set binary magic data
1250
ped_device_close( lp_device );
1253
if ( 0 == memcmp( magic1, "LABELONE", 8 )
1254
&& 0 == memcmp( magic2, "LVM2", 4 ) )
1256
return GParted::FS_LVM2_PV ;
1261
const Sector BTRFS_SUPER_INFO_SIZE = 4096 ;
1262
const Sector BTRFS_SUPER_INFO_OFFSET = (64 * 1024) ;
1263
const char* const BTRFS_SIGNATURE = "_BHRfS_M" ;
1265
char buf_btrfs[BTRFS_SUPER_INFO_SIZE] ;
1267
ped_device_open( lp_device ) ;
1268
ped_geometry_read( & lp_partition ->geom
1270
, (BTRFS_SUPER_INFO_OFFSET / lp_device ->sector_size)
1271
, (BTRFS_SUPER_INFO_SIZE / lp_device ->sector_size)
1273
memcpy(magic1, buf_btrfs+64, strlen(BTRFS_SIGNATURE) ) ; //set binary magic data
1274
ped_device_close( lp_device ) ;
1276
if ( 0 == memcmp( magic1, BTRFS_SIGNATURE, strlen(BTRFS_SIGNATURE) ) )
1278
return GParted::FS_BTRFS ;
1281
//no file system found....
1282
temp = _( "Unable to detect file system! Possible reasons are:" ) ;
1284
temp += _( "The file system is damaged" ) ;
1286
temp += _( "The file system is unknown to GParted" ) ;
1288
temp += _( "There is no file system available (unformatted)" ) ;
1290
/* TO TRANSLATORS: looks like The device entry /dev/sda5 is missing */
1291
temp += String::ucompose( _( "The device entry %1 is missing" ), get_partition_path( lp_partition ) ) ;
1293
partition_temp .messages .push_back( temp ) ;
1295
return GParted::FS_UNKNOWN ;
1298
void GParted_Core::read_label( Partition & partition )
1300
if ( partition .type != TYPE_EXTENDED )
1302
switch( get_fs( partition .filesystem ) .read_label )
1305
if ( set_proper_filesystem( partition .filesystem ) )
1306
p_filesystem ->read_label( partition ) ;
1308
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
1319
void GParted_Core::read_uuid( Partition & partition )
1321
if ( partition .type != TYPE_EXTENDED )
1323
switch( get_fs( partition .filesystem ) .read_uuid )
1326
if ( set_proper_filesystem( partition .filesystem ) )
1327
p_filesystem ->read_uuid( partition ) ;
1336
void GParted_Core::insert_unallocated( const Glib::ustring & device_path,
1337
std::vector<Partition> & partitions,
1340
Byte_Value sector_size,
1341
bool inside_extended )
1343
partition_temp .Reset() ;
1344
partition_temp .Set_Unallocated( device_path, 0, 0, sector_size, inside_extended ) ;
1346
//if there are no partitions at all..
1347
if ( partitions .empty() )
1349
partition_temp .sector_start = start ;
1350
partition_temp .sector_end = end ;
1352
partitions .push_back( partition_temp );
1357
//start <---> first partition start
1358
if ( (partitions .front() .sector_start - start) > (MEBIBYTE / sector_size) )
1360
partition_temp .sector_start = start ;
1361
partition_temp .sector_end = partitions .front() .sector_start -1 ;
1363
partitions .insert( partitions .begin(), partition_temp );
1366
//look for gaps in between
1367
for ( unsigned int t =0 ; t < partitions .size() -1 ; t++ )
1369
if ( ( ( partitions[ t + 1 ] .sector_start - partitions[ t ] .sector_end - 1 ) > (MEBIBYTE / sector_size) )
1370
|| ( ( partitions[ t + 1 ] .type != TYPE_LOGICAL ) // Only show exactly 1 MiB if following partition is not logical.
1371
&& ( ( partitions[ t + 1 ] .sector_start - partitions[ t ] .sector_end - 1 ) == (MEBIBYTE / sector_size) )
1375
partition_temp .sector_start = partitions[ t ] .sector_end +1 ;
1376
partition_temp .sector_end = partitions[ t +1 ] .sector_start -1 ;
1378
partitions .insert( partitions .begin() + ++t, partition_temp );
1382
//last partition end <---> end
1383
if ( (end - partitions .back() .sector_end) >= (MEBIBYTE / sector_size) )
1385
partition_temp .sector_start = partitions .back() .sector_end +1 ;
1386
partition_temp .sector_end = end ;
1388
partitions .push_back( partition_temp );
1392
void GParted_Core::set_mountpoints( std::vector<Partition> & partitions )
1394
#ifndef USE_LIBPARTED_DMRAID
1395
DMRaid dmraid ; //Use cache of dmraid device information
1397
LVM2_PV_Info lvm2_pv_info ;
1398
for ( unsigned int t = 0 ; t < partitions .size() ; t++ )
1400
if ( ( partitions[ t ] .type == GParted::TYPE_PRIMARY ||
1401
partitions[ t ] .type == GParted::TYPE_LOGICAL
1403
partitions[ t ] .filesystem != GParted::FS_LINUX_SWAP &&
1404
partitions[ t ] .filesystem != GParted::FS_LVM2_PV &&
1405
partitions[ t ] .filesystem != GParted::FS_LUKS
1408
if ( partitions[ t ] .busy )
1410
#ifndef USE_LIBPARTED_DMRAID
1411
//Handle dmraid devices differently because there may be more
1412
// than one partition name.
1413
// E.g., there might be names with and/or without a 'p' between
1414
// the device name and partition number.
1415
if ( dmraid .is_dmraid_device( partitions[ t ] .device_path ) )
1417
//Try device_name + partition_number
1418
iter_mp = mount_info .find( partitions[ t ] .device_path + Utils::num_to_str( partitions[ t ] .partition_number ) ) ;
1419
if ( iter_mp != mount_info .end() )
1421
partitions[ t ] .add_mountpoints( iter_mp ->second ) ;
1424
//Try device_name + p + partition_number
1425
iter_mp = mount_info .find( partitions[ t ] .device_path + "p" + Utils::num_to_str( partitions[ t ] .partition_number ) ) ;
1426
if ( iter_mp != mount_info .end() )
1428
partitions[ t ] .add_mountpoints( iter_mp ->second ) ;
1435
//Normal device, not DMRaid device
1436
for ( unsigned int i = 0 ; i < partitions[ t ] .get_paths() .size() ; i++ )
1438
iter_mp = mount_info .find( partitions[ t ] .get_paths()[ i ] ) ;
1439
if ( iter_mp != mount_info .end() )
1441
partitions[ t ] .add_mountpoints( iter_mp ->second ) ;
1445
#ifndef USE_LIBPARTED_DMRAID
1449
if ( partitions[ t ] .get_mountpoints() .empty() )
1450
partitions[ t ] .messages .push_back( _("Unable to find mount point") ) ;
1454
iter_mp = fstab_info .find( partitions[ t ] .get_path() );
1455
if ( iter_mp != fstab_info .end() )
1456
partitions[ t ] .add_mountpoints( iter_mp ->second ) ;
1459
else if ( partitions[ t ] .type == GParted::TYPE_EXTENDED )
1460
set_mountpoints( partitions[ t ] .logicals ) ;
1461
else if ( partitions[ t ] .filesystem == GParted::FS_LVM2_PV )
1463
Glib::ustring vgname = lvm2_pv_info. get_vg_name( partitions[t].get_path() ) ;
1464
if ( ! vgname .empty() )
1465
partitions[ t ] .add_mountpoint( vgname ) ;
1470
void GParted_Core::set_used_sectors( std::vector<Partition> & partitions )
1472
struct statvfs sfs ;
1474
for ( unsigned int t = 0 ; t < partitions .size() ; t++ )
1476
if ( partitions[ t ] .filesystem != GParted::FS_LINUX_SWAP &&
1477
partitions[ t ] .filesystem != GParted::FS_LUKS &&
1478
partitions[ t ] .filesystem != GParted::FS_UNKNOWN
1481
if ( partitions[ t ] .type == GParted::TYPE_PRIMARY ||
1482
partitions[ t ] .type == GParted::TYPE_LOGICAL )
1484
if ( partitions[ t ] .busy && partitions[t] .filesystem != GParted::FS_LVM2_PV )
1486
if ( partitions[ t ] .get_mountpoints() .size() > 0 )
1488
if ( statvfs( partitions[ t ] .get_mountpoint() .c_str(), &sfs ) == 0 )
1489
partitions[ t ] .Set_Unused( sfs .f_bfree * (sfs .f_bsize / partitions[ t ] .sector_size) ) ;
1491
partitions[ t ] .messages .push_back(
1493
partitions[ t ] .get_mountpoint() +
1495
Glib::strerror( errno ) ) ;
1500
switch( get_fs( partitions[ t ] .filesystem ) .read )
1502
case GParted::FS::EXTERNAL :
1503
if ( set_proper_filesystem( partitions[ t ] .filesystem ) )
1504
p_filesystem ->set_used_sectors( partitions[ t ] ) ;
1506
#ifdef HAVE_LIBPARTED_FS_RESIZE
1507
case GParted::FS::LIBPARTED :
1508
LP_set_used_sectors( partitions[ t ] ) ;
1517
if ( partitions[ t ] .sectors_used == -1 )
1519
temp = _("Unable to read the contents of this file system!") ;
1521
temp += _("Because of this some operations may be unavailable.") ;
1522
if ( ! Utils::get_filesystem_software( partitions[ t ] .filesystem ) .empty() )
1525
temp += _( "The cause might be a missing software package.") ;
1527
/*TO TRANSLATORS: looks like The following list of software packages is required for NTFS file system support: ntfsprogs. */
1528
temp += String::ucompose( _("The following list of software packages is required for %1 file system support: %2."),
1529
Utils::get_filesystem_string( partitions[ t ] .filesystem ),
1530
Utils::get_filesystem_software( partitions[ t ] .filesystem )
1533
partitions[ t ] .messages .push_back( temp ) ;
1536
else if ( partitions[ t ] .type == GParted::TYPE_EXTENDED )
1537
set_used_sectors( partitions[ t ] .logicals ) ;
1542
#ifdef HAVE_LIBPARTED_FS_RESIZE
1543
void GParted_Core::LP_set_used_sectors( Partition & partition )
1545
PedFileSystem *fs = NULL;
1546
PedConstraint *constraint = NULL;
1550
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
1554
fs = ped_file_system_open( & lp_partition ->geom );
1558
constraint = ped_file_system_get_resize_constraint( fs ) ;
1561
partition .Set_Unused( partition .get_sector_length() - constraint ->min_size ) ;
1563
ped_constraint_destroy( constraint );
1566
ped_file_system_close( fs ) ;
1573
void GParted_Core::set_flags( Partition & partition )
1575
for ( unsigned int t = 0 ; t < flags .size() ; t++ )
1576
if ( ped_partition_is_flag_available( lp_partition, flags[ t ] ) &&
1577
ped_partition_get_flag( lp_partition, flags[ t ] ) )
1578
partition .flags .push_back( ped_partition_flag_get_name( flags[ t ] ) ) ;
1581
bool GParted_Core::create( const Device & device, Partition & new_partition, OperationDetail & operationdetail )
1583
if ( new_partition .type == GParted::TYPE_EXTENDED )
1585
return create_partition( new_partition, operationdetail ) ;
1587
else if ( create_partition( new_partition, operationdetail, (get_fs( new_partition .filesystem ) .MIN / new_partition .sector_size) ) )
1589
if ( new_partition .filesystem == GParted::FS_UNFORMATTED )
1592
return set_partition_type( new_partition, operationdetail ) &&
1593
create_filesystem( new_partition, operationdetail ) ;
1599
bool GParted_Core::create_partition( Partition & new_partition, OperationDetail & operationdetail, Sector min_size )
1601
operationdetail .add_child( OperationDetail( _("create empty partition") ) ) ;
1603
new_partition .partition_number = 0 ;
1605
if ( open_device_and_disk( new_partition .device_path ) )
1607
PedPartitionType type;
1608
lp_partition = NULL ;
1609
PedConstraint *constraint = NULL ;
1610
PedFileSystemType* fs_type = NULL ;
1612
//create new partition
1613
switch ( new_partition .type )
1615
case GParted::TYPE_PRIMARY:
1616
type = PED_PARTITION_NORMAL ;
1618
case GParted::TYPE_LOGICAL:
1619
type = PED_PARTITION_LOGICAL ;
1621
case GParted::TYPE_EXTENDED:
1622
type = PED_PARTITION_EXTENDED ;
1626
type = PED_PARTITION_FREESPACE;
1629
if ( new_partition .type != GParted::TYPE_EXTENDED )
1630
fs_type = ped_file_system_type_get( "ext2" ) ;
1632
lp_partition = ped_partition_new( lp_disk,
1635
new_partition .sector_start,
1636
new_partition .sector_end ) ;
1640
if ( new_partition .alignment == ALIGN_STRICT
1641
|| new_partition .alignment == ALIGN_MEBIBYTE
1644
PedGeometry *geom = ped_geometry_new( lp_device,
1645
new_partition .sector_start,
1646
new_partition .get_sector_length() ) ;
1649
constraint = ped_constraint_exact( geom ) ;
1652
constraint = ped_constraint_any( lp_device );
1657
&& new_partition .filesystem != FS_XFS // Permit copying to smaller xfs partition
1659
constraint ->min_size = min_size ;
1661
if ( ped_disk_add_partition( lp_disk, lp_partition, constraint ) && commit() )
1663
Glib::ustring partition_path = get_partition_path( lp_partition ) ;
1664
new_partition .add_path( partition_path, true ) ;
1666
new_partition .partition_number = lp_partition ->num ;
1667
new_partition .sector_start = lp_partition ->geom .start ;
1668
new_partition .sector_end = lp_partition ->geom .end ;
1670
operationdetail .get_last_child() .add_child( OperationDetail(
1671
String::ucompose( _("path: %1"), new_partition .get_path() ) + "\n" +
1672
String::ucompose( _("start: %1"), new_partition .sector_start ) + "\n" +
1673
String::ucompose( _("end: %1"), new_partition .sector_end ) + "\n" +
1674
String::ucompose( _("size: %1 (%2)"),
1675
new_partition .get_sector_length(),
1676
Utils::format_size( new_partition .get_sector_length(), new_partition .sector_size ) ),
1681
ped_constraint_destroy( constraint );
1685
close_device_and_disk() ;
1688
bool succes = new_partition .partition_number > 0
1689
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
1690
&& erase_filesystem_signatures( new_partition )
1694
#ifndef USE_LIBPARTED_DMRAID
1695
//create dev map entries if dmraid
1697
if ( succes && dmraid .is_dmraid_device( new_partition .device_path ) )
1698
succes = dmraid .create_dev_map_entries( new_partition, operationdetail .get_last_child() ) ;
1701
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
1706
bool GParted_Core::create_filesystem( const Partition & partition, OperationDetail & operationdetail )
1708
/*TO TRANSLATORS: looks like create new ext3 file system */
1709
operationdetail .add_child( OperationDetail( String::ucompose(
1710
_("create new %1 file system"),
1711
Utils::get_filesystem_string( partition .filesystem ) ) ) ) ;
1713
bool succes = false ;
1714
switch ( get_fs( partition .filesystem ) .create )
1716
case GParted::FS::NONE:
1718
case GParted::FS::GPARTED:
1720
#ifndef HAVE_LIBPARTED_3_0_PLUS
1721
case GParted::FS::LIBPARTED:
1724
case GParted::FS::EXTERNAL:
1725
succes = set_proper_filesystem( partition .filesystem ) &&
1726
p_filesystem ->create( partition, operationdetail .get_last_child() ) ;
1734
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
1738
bool GParted_Core::format( const Partition & partition, OperationDetail & operationdetail )
1740
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
1741
//remove all file system signatures...
1742
erase_filesystem_signatures( partition ) ;
1745
return set_partition_type( partition, operationdetail ) && create_filesystem( partition, operationdetail ) ;
1748
bool GParted_Core::Delete( const Partition & partition, OperationDetail & operationdetail )
1750
operationdetail .add_child( OperationDetail( _("delete partition") ) ) ;
1752
bool succes = false ;
1753
if ( open_device_and_disk( partition .device_path ) )
1755
if ( partition .type == TYPE_EXTENDED )
1756
lp_partition = ped_disk_extended_partition( lp_disk ) ;
1758
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
1760
succes = ped_disk_delete_partition( lp_disk, lp_partition ) && commit() ;
1762
close_device_and_disk() ;
1765
#ifndef USE_LIBPARTED_DMRAID
1766
//delete partition dev mapper entry, and delete and recreate all other affected dev mapper entries if dmraid
1768
if ( succes && dmraid .is_dmraid_device( partition .device_path ) )
1770
//Open disk handle before and close after to prevent application crash.
1771
if ( open_device_and_disk( partition .device_path ) )
1773
if ( ! dmraid .delete_affected_dev_map_entries( partition, operationdetail .get_last_child() ) )
1774
succes = false ; //comand failed
1776
if ( ! dmraid .create_dev_map_entries( partition, operationdetail .get_last_child() ) )
1777
succes = false ; //command failed
1779
close_device_and_disk() ;
1784
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
1788
bool GParted_Core::label_partition( const Partition & partition, OperationDetail & operationdetail )
1790
if( partition .label .empty() ) {
1791
operationdetail .add_child( OperationDetail( String::ucompose(
1792
_("Clear partition label on %1"),
1793
partition .get_path()
1796
operationdetail .add_child( OperationDetail( String::ucompose(
1797
_("Set partition label to \"%1\" on %2"),
1798
partition .label, partition .get_path()
1802
bool succes = false ;
1803
if ( partition .type != TYPE_EXTENDED )
1805
switch( get_fs( partition .filesystem ) .write_label )
1808
succes = set_proper_filesystem( partition .filesystem ) &&
1809
p_filesystem ->write_label( partition, operationdetail .get_last_child() ) ;
1811
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
1821
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
1826
bool GParted_Core::change_uuid( const Partition & partition, OperationDetail & operationdetail )
1828
if ( partition .uuid == UUID_RANDOM_NTFS_HALF ) {
1829
operationdetail .add_child( OperationDetail( String::ucompose(
1830
_("Set half of the UUID on %1 to a new, random value"),
1831
partition .get_path()
1834
operationdetail .add_child( OperationDetail( String::ucompose(
1835
_("Set UUID on %1 to a new, random value"),
1836
partition .get_path()
1840
bool succes = false ;
1841
if ( partition .type != TYPE_EXTENDED )
1843
switch( get_fs( partition .filesystem ) .write_uuid )
1846
succes = set_proper_filesystem( partition .filesystem ) &&
1847
p_filesystem ->write_uuid( partition, operationdetail .get_last_child() ) ;
1855
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
1860
bool GParted_Core::resize_move( const Device & device,
1861
const Partition & partition_old,
1862
Partition & partition_new,
1863
OperationDetail & operationdetail )
1865
if ( (partition_new .alignment == ALIGN_STRICT)
1866
|| (partition_new .alignment == ALIGN_MEBIBYTE)
1867
|| partition_new .strict_start
1868
|| calculate_exact_geom( partition_old, partition_new, operationdetail )
1871
if ( partition_old .type == TYPE_EXTENDED )
1872
return resize_move_partition( partition_old, partition_new, operationdetail ) ;
1874
if ( partition_new .sector_start == partition_old .sector_start )
1875
return resize( partition_old, partition_new, operationdetail ) ;
1877
if ( partition_new .get_sector_length() == partition_old .get_sector_length() )
1878
return move( device, partition_old, partition_new, operationdetail ) ;
1881
if ( partition_new .get_sector_length() > partition_old .get_sector_length() )
1883
//first move, then grow. Since old.length < new.length and new.start is valid, temp is valid.
1884
temp = partition_new ;
1885
temp .sector_end = temp .sector_start + partition_old .get_sector_length() -1 ;
1888
if ( partition_new .get_sector_length() < partition_old .get_sector_length() )
1890
//first shrink, then move. Since new.length < old.length and old.start is valid, temp is valid.
1891
temp = partition_old ;
1892
temp .sector_end = partition_old .sector_start + partition_new .get_sector_length() -1 ;
1895
PartitionAlignment previous_alignment = temp .alignment ;
1896
temp .alignment = ALIGN_STRICT ;
1897
bool succes = resize_move( device, partition_old, temp, operationdetail ) ;
1898
temp .alignment = previous_alignment ;
1900
return succes && resize_move( device, temp, partition_new, operationdetail ) ;
1906
bool GParted_Core::move( const Device & device,
1907
const Partition & partition_old,
1908
const Partition & partition_new,
1909
OperationDetail & operationdetail )
1911
if ( partition_old .get_sector_length() != partition_new .get_sector_length() )
1913
operationdetail .add_child( OperationDetail(
1914
/* TO TRANSLATORS: moving requires old and new length to be the same
1915
* means that the length in bytes of the old partition and new partition
1916
* must be the same. If the sector sizes of the old partition and the
1917
* new partition are the same, then the length in sectors must be the same.
1919
_("moving requires old and new length to be the same"), STATUS_ERROR, FONT_ITALIC ) ) ;
1924
bool succes = false ;
1925
if ( check_repair_filesystem( partition_old, operationdetail ) )
1927
//NOTE: Logical partitions are preceded by meta data. To prevent this
1928
// meta data from being overwritten we first expand the partition to
1929
// encompass all of the space involved in the move. In this way we
1930
// prevent overwriting the meta data for this partition when we move
1931
// this partition to the left. We also prevent overwriting the meta
1932
// data of a following partition when we move this partition to the
1934
Partition partition_all_space = partition_old ;
1935
partition_all_space .alignment = ALIGN_STRICT ;
1936
if ( partition_new .sector_start < partition_all_space. sector_start )
1937
partition_all_space .sector_start = partition_new. sector_start ;
1938
if ( partition_new .sector_end > partition_all_space.sector_end )
1939
partition_all_space .sector_end = partition_new. sector_end ;
1941
//Make old partition all encompassing and if move file system fails
1942
// then return partition table to original state
1943
if ( resize_move_partition( partition_old, partition_all_space, operationdetail ) )
1945
//Note move of file system is from old values to new values, not from
1946
// the all encompassing values.
1947
if ( ! move_filesystem( partition_old, partition_new, operationdetail ) )
1949
operationdetail .add_child( OperationDetail( _("rollback last change to the partition table") ) ) ;
1951
Partition partition_restore = partition_old ;
1952
partition_restore .alignment = ALIGN_STRICT ; //Ensure that old partition boundaries are not modified
1953
if ( resize_move_partition( partition_all_space, partition_restore, operationdetail .get_last_child() ) )
1954
operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
1956
operationdetail .get_last_child() .set_status( STATUS_ERROR ) ;
1962
//Make new partition from all encompassing partition
1963
succes = succes && resize_move_partition( partition_all_space, partition_new, operationdetail ) ;
1966
&& update_bootsector( partition_new, operationdetail )
1967
&& ( //Do not maximize file system if FS not linux-swap and new size <= old
1968
( partition_new .filesystem != FS_LINUX_SWAP //linux-swap is recreated, not moved
1969
&& partition_new .get_sector_length() <= partition_old .get_sector_length()
1971
|| ( check_repair_filesystem( partition_new, operationdetail )
1972
&& maximize_filesystem( partition_new, operationdetail )
1982
bool GParted_Core::move_filesystem( const Partition & partition_old,
1983
const Partition & partition_new,
1984
OperationDetail & operationdetail )
1986
if ( partition_new .sector_start < partition_old .sector_start )
1987
operationdetail .add_child( OperationDetail( _("move file system to the left") ) ) ;
1988
else if ( partition_new .sector_start > partition_old .sector_start )
1989
operationdetail .add_child( OperationDetail( _("move file system to the right") ) ) ;
1992
operationdetail .add_child( OperationDetail( _("move file system") ) ) ;
1993
operationdetail .get_last_child() .add_child(
1994
OperationDetail( _("new and old file system have the same position. Hence skipping this operation"),
1998
operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
2002
bool succes = false ;
2003
switch ( get_fs( partition_old .filesystem ) .move )
2005
case GParted::FS::NONE:
2007
case GParted::FS::GPARTED:
2009
if ( partition_new .test_overlap( partition_old ) )
2011
if ( copy_filesystem_simulation( partition_old, partition_new, operationdetail .get_last_child() ) )
2013
operationdetail .get_last_child() .add_child( OperationDetail( _("perform real move") ) ) ;
2016
succes = copy_filesystem( partition_old,
2018
operationdetail .get_last_child() .get_last_child(),
2021
operationdetail .get_last_child() .get_last_child()
2022
.set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2025
rollback_transaction( partition_old,
2027
operationdetail .get_last_child(),
2030
check_repair_filesystem( partition_old, operationdetail ) ;
2035
succes = copy_filesystem( partition_old, partition_new, operationdetail .get_last_child() ) ;
2038
#ifdef HAVE_LIBPARTED_FS_RESIZE
2039
case GParted::FS::LIBPARTED:
2040
succes = resize_move_filesystem_using_libparted( partition_old,
2042
operationdetail .get_last_child() ) ;
2045
case GParted::FS::EXTERNAL:
2046
succes = set_proper_filesystem( partition_new .filesystem ) &&
2047
p_filesystem ->move( partition_old
2049
, operationdetail .get_last_child()
2057
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2061
#ifdef HAVE_LIBPARTED_FS_RESIZE
2062
bool GParted_Core::resize_move_filesystem_using_libparted( const Partition & partition_old,
2063
const Partition & partition_new,
2064
OperationDetail & operationdetail )
2066
operationdetail .add_child( OperationDetail( _("using libparted"), STATUS_NONE ) ) ;
2068
bool return_value = false ;
2069
if ( open_device_and_disk( partition_old .device_path ) )
2071
PedFileSystem * fs = NULL ;
2072
PedGeometry * lp_geom = NULL ;
2074
lp_geom = ped_geometry_new( lp_device,
2075
partition_old .sector_start,
2076
partition_old .get_sector_length() ) ;
2079
fs = ped_file_system_open( lp_geom );
2083
lp_geom = ped_geometry_new( lp_device,
2084
partition_new .sector_start,
2085
partition_new .get_sector_length() ) ;
2087
return_value = ped_file_system_resize( fs, lp_geom, NULL ) && commit() ;
2089
ped_file_system_close( fs );
2093
close_device_and_disk() ;
2096
return return_value ;
2100
bool GParted_Core::resize( const Partition & partition_old,
2101
const Partition & partition_new,
2102
OperationDetail & operationdetail )
2104
if ( partition_old .sector_start != partition_new .sector_start )
2106
operationdetail .add_child( OperationDetail(
2107
_("resizing requires old and new start to be the same"), STATUS_ERROR, FONT_ITALIC ) ) ;
2112
bool succes = false ;
2113
if ( check_repair_filesystem( partition_new, operationdetail ) )
2117
if ( succes && partition_new .get_sector_length() < partition_old .get_sector_length() )
2118
succes = resize_filesystem( partition_old, partition_new, operationdetail ) ;
2121
succes = resize_move_partition( partition_old, partition_new, operationdetail ) ;
2123
//expand file system to fit exactly in partition
2124
if ( ! ( //Do not maximize file system if FS not linux-swap and new size <= old
2125
( partition_new .filesystem != FS_LINUX_SWAP //linux-swap is recreated, not resized
2126
&& partition_new .get_sector_length() <= partition_old .get_sector_length()
2128
|| ( check_repair_filesystem( partition_new, operationdetail )
2129
&& maximize_filesystem( partition_new, operationdetail )
2141
bool GParted_Core::resize_move_partition( const Partition & partition_old,
2142
const Partition & partition_new,
2143
OperationDetail & operationdetail )
2145
//i'm not too happy with this, but i think it is the correct way from a i18n POV
2153
MOVE_RIGHT_GROW = 5,
2154
MOVE_RIGHT_SHRINK = 6,
2156
MOVE_LEFT_SHRINK = 8
2158
Action action = NONE ;
2160
if ( partition_new .get_sector_length() > partition_old .get_sector_length() )
2162
else if ( partition_new .get_sector_length() < partition_old .get_sector_length() )
2165
if ( partition_new .sector_start > partition_old .sector_start &&
2166
partition_new .sector_end > partition_old .sector_end )
2167
action = action == GROW ? MOVE_RIGHT_GROW : action == SHRINK ? MOVE_RIGHT_SHRINK : MOVE_RIGHT ;
2168
else if ( partition_new .sector_start < partition_old .sector_start &&
2169
partition_new .sector_end < partition_old .sector_end )
2170
action = action == GROW ? MOVE_LEFT_GROW : action == SHRINK ? MOVE_LEFT_SHRINK : MOVE_LEFT ;
2172
Glib::ustring description ;
2176
description = _("resize/move partition") ;
2179
description = _("move partition to the right") ;
2182
description = _("move partition to the left") ;
2185
description = _("grow partition from %1 to %2") ;
2188
description = _("shrink partition from %1 to %2") ;
2190
case MOVE_RIGHT_GROW :
2191
description = _("move partition to the right and grow it from %1 to %2") ;
2193
case MOVE_RIGHT_SHRINK :
2194
description = _("move partition to the right and shrink it from %1 to %2") ;
2196
case MOVE_LEFT_GROW :
2197
description = _("move partition to the left and grow it from %1 to %2") ;
2199
case MOVE_LEFT_SHRINK :
2200
description = _("move partition to the left and shrink it from %1 to %2") ;
2204
if ( ! description .empty() && action != NONE && action != MOVE_LEFT && action != MOVE_RIGHT )
2205
description = String::ucompose( description,
2206
Utils::format_size( partition_old .get_sector_length(), partition_old .sector_size ),
2207
Utils::format_size( partition_new .get_sector_length(), partition_new .sector_size ) ) ;
2209
operationdetail .add_child( OperationDetail( description ) ) ;
2212
if ( action == NONE )
2214
operationdetail .get_last_child() .add_child(
2215
OperationDetail( _("new and old partition have the same size and position. Hence skipping this operation"),
2219
operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
2223
operationdetail .get_last_child() .add_child(
2225
String::ucompose( _("old start: %1"), partition_old .sector_start ) + "\n" +
2226
String::ucompose( _("old end: %1"), partition_old .sector_end ) + "\n" +
2227
String::ucompose( _("old size: %1 (%2)"),
2228
partition_old .get_sector_length(),
2229
Utils::format_size( partition_old .get_sector_length(), partition_old .sector_size ) ),
2233
//finally the actual resize/move
2234
bool return_value = false ;
2236
PedConstraint *constraint = NULL ;
2237
lp_partition = NULL ;
2239
//sometimes the lp_partition ->geom .start,end and length values display random numbers
2240
//after going out of the 'if ( lp_partition)' scope. That's why we use some variables here.
2241
Sector new_start = -1, new_end = -1 ;
2243
if ( open_device_and_disk( partition_old .device_path ) )
2245
if ( partition_old .type == GParted::TYPE_EXTENDED )
2246
lp_partition = ped_disk_extended_partition( lp_disk ) ;
2248
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition_old .get_sector() ) ;
2252
if ( (partition_new .alignment == ALIGN_STRICT)
2253
|| (partition_new .alignment == ALIGN_MEBIBYTE)
2254
|| partition_new .strict_start
2256
PedGeometry *geom = ped_geometry_new( lp_device,
2257
partition_new .sector_start,
2258
partition_new .get_sector_length() ) ;
2259
constraint = ped_constraint_exact( geom ) ;
2262
constraint = ped_constraint_any( lp_device ) ;
2266
if ( ped_disk_set_partition_geom( lp_disk,
2269
partition_new .sector_start,
2270
partition_new .sector_end ) )
2272
new_start = lp_partition ->geom .start ;
2273
new_end = lp_partition ->geom .end ;
2275
return_value = commit() ;
2278
ped_constraint_destroy( constraint );
2282
close_device_and_disk() ;
2287
//Change to partition succeeded
2288
operationdetail .get_last_child() .add_child(
2290
String::ucompose( _("new start: %1"), new_start ) + "\n" +
2291
String::ucompose( _("new end: %1"), new_end ) + "\n" +
2292
String::ucompose( _("new size: %1 (%2)"),
2293
new_end - new_start + 1,
2294
Utils::format_size( new_end - new_start + 1, partition_new .sector_size ) ),
2298
#ifndef USE_LIBPARTED_DMRAID
2299
//update dev mapper entry if partition is dmraid.
2301
if ( return_value && dmraid .is_dmraid_device( partition_new .device_path ) )
2303
//Open disk handle before and close after to prevent application crash.
2304
if ( open_device_and_disk( partition_new .device_path ) )
2306
return_value = dmraid .update_dev_map_entry( partition_new, operationdetail .get_last_child() ) ;
2307
close_device_and_disk() ;
2314
//Change to partition failed
2315
operationdetail .get_last_child() .add_child(
2317
String::ucompose( _("requested start: %1"), partition_new .sector_start ) + "\n" +
2318
String::ucompose( _("requested end: %1"), partition_new . sector_end ) + "\n" +
2319
String::ucompose( _("requested size: %1 (%2)"),
2320
partition_new .get_sector_length(),
2321
Utils::format_size( partition_new .get_sector_length(), partition_new .sector_size ) ),
2327
operationdetail .get_last_child() .set_status( return_value ? STATUS_SUCCES : STATUS_ERROR ) ;
2329
return return_value ;
2332
bool GParted_Core::resize_filesystem( const Partition & partition_old,
2333
const Partition & partition_new,
2334
OperationDetail & operationdetail,
2335
bool fill_partition )
2337
//by default 'grow' to accomodate expand_filesystem()
2338
GParted::FS::Support action = get_fs( partition_old .filesystem ) .grow ;
2340
if ( ! fill_partition )
2342
if ( partition_new .get_sector_length() < partition_old .get_sector_length() )
2344
operationdetail .add_child( OperationDetail( _("shrink file system") ) ) ;
2345
action = get_fs( partition_old .filesystem ) .shrink ;
2347
else if ( partition_new .get_sector_length() > partition_old .get_sector_length() )
2348
operationdetail .add_child( OperationDetail( _("grow file system") ) ) ;
2351
operationdetail .add_child( OperationDetail( _("resize file system") ) ) ;
2352
operationdetail .get_last_child() .add_child(
2354
_("new and old file system have the same size. Hence skipping this operation"),
2358
operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
2363
bool succes = false ;
2366
case GParted::FS::NONE:
2368
case GParted::FS::GPARTED:
2370
#ifdef HAVE_LIBPARTED_FS_RESIZE
2371
case GParted::FS::LIBPARTED:
2372
succes = resize_move_filesystem_using_libparted( partition_old,
2374
operationdetail .get_last_child() ) ;
2377
case GParted::FS::EXTERNAL:
2378
succes = set_proper_filesystem( partition_new .filesystem ) &&
2379
p_filesystem ->resize( partition_new,
2380
operationdetail .get_last_child(),
2388
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2392
bool GParted_Core::maximize_filesystem( const Partition & partition, OperationDetail & operationdetail )
2394
operationdetail .add_child( OperationDetail( _("grow file system to fill the partition") ) ) ;
2396
if ( get_fs( partition .filesystem ) .grow == GParted::FS::NONE )
2398
operationdetail .get_last_child() .add_child(
2399
OperationDetail( _("growing is not available for this file system"),
2403
operationdetail .get_last_child() .set_status( STATUS_N_A ) ;
2407
return resize_filesystem( partition, partition, operationdetail, true ) ;
2410
bool GParted_Core::copy( const Partition & partition_src,
2411
Partition & partition_dst,
2412
Byte_Value min_size,
2413
OperationDetail & operationdetail )
2415
if ( partition_dst .get_byte_length() < partition_src .get_byte_length()
2416
&& partition_src .filesystem != FS_XFS // Permit copying to smaller xfs partition
2419
operationdetail .add_child( OperationDetail(
2420
_("the destination is smaller than the source partition"), STATUS_ERROR, FONT_ITALIC ) ) ;
2425
if ( check_repair_filesystem( partition_src, operationdetail ) )
2427
bool succes = true ;
2428
if ( partition_dst .status == GParted::STAT_COPY )
2430
/* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
2431
succes = create_partition( partition_dst, operationdetail, ( (min_size + (partition_dst .sector_size - 1)) / partition_dst .sector_size ) ) ;
2434
if ( succes && set_partition_type( partition_dst, operationdetail ) )
2436
operationdetail .add_child( OperationDetail(
2437
String::ucompose( _("copy file system of %1 to %2"),
2438
partition_src .get_path(),
2439
partition_dst .get_path() ) ) ) ;
2441
switch ( get_fs( partition_dst .filesystem ) .copy )
2443
case GParted::FS::GPARTED :
2444
succes = copy_filesystem( partition_src,
2446
operationdetail .get_last_child() ) ;
2449
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
2450
case GParted::FS::LIBPARTED :
2451
//FIXME: see if copying through libparted has any advantages
2455
case GParted::FS::EXTERNAL :
2456
succes = set_proper_filesystem( partition_dst .filesystem ) &&
2457
p_filesystem ->copy( partition_src .get_path(),
2458
partition_dst .get_path(),
2459
operationdetail .get_last_child() ) ;
2467
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2470
&& update_bootsector( partition_dst, operationdetail )
2471
&& ( //Do not maximize file system if FS not linux-swap and destination size <= source
2472
( partition_dst .filesystem != FS_LINUX_SWAP //linux-swap is recreated, not copied
2473
&& partition_dst .get_sector_length() <= partition_src .get_sector_length()
2475
|| ( check_repair_filesystem( partition_dst, operationdetail )
2476
&& maximize_filesystem( partition_dst, operationdetail )
2486
bool GParted_Core::copy_filesystem_simulation( const Partition & partition_src,
2487
const Partition & partition_dst,
2488
OperationDetail & operationdetail )
2490
operationdetail .add_child( OperationDetail( _("perform read-only test") ) ) ;
2492
bool succes = copy_filesystem( partition_src, partition_dst, operationdetail .get_last_child(), true ) ;
2494
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2498
bool GParted_Core::copy_filesystem( const Partition & partition_src,
2499
const Partition & partition_dst,
2500
OperationDetail & operationdetail,
2504
return copy_filesystem( partition_src .device_path,
2505
partition_dst .device_path,
2506
partition_src .sector_start,
2507
partition_dst .sector_start,
2508
partition_src .sector_size,
2509
partition_dst .sector_size,
2510
partition_src .get_byte_length(),
2516
bool GParted_Core::copy_filesystem( const Partition & partition_src,
2517
const Partition & partition_dst,
2518
OperationDetail & operationdetail,
2519
Byte_Value & total_done )
2521
return copy_filesystem( partition_src .device_path,
2522
partition_dst .device_path,
2523
partition_src .sector_start,
2524
partition_dst .sector_start,
2525
partition_src .sector_size,
2526
partition_dst .sector_size,
2527
partition_src .get_byte_length(),
2533
bool GParted_Core::copy_filesystem( const Glib::ustring & src_device,
2534
const Glib::ustring & dst_device,
2537
Byte_Value src_sector_size,
2538
Byte_Value dst_sector_size,
2539
Byte_Value src_length,
2540
OperationDetail & operationdetail,
2542
Byte_Value & total_done )
2544
operationdetail .add_child( OperationDetail( _("using internal algorithm"), STATUS_NONE ) ) ;
2545
operationdetail .add_child( OperationDetail(
2546
String::ucompose( readonly ?
2547
/*TO TRANSLATORS: looks like read 1.00 MiB */
2549
/*TO TRANSLATORS: looks like copy 1.00 MiB */
2551
Utils::format_size( src_length, 1 ) ),
2554
operationdetail .add_child( OperationDetail( _("finding optimal block size"), STATUS_NONE ) ) ;
2556
Byte_Value benchmark_blocksize = readonly ? (2 * MEBIBYTE) : (1 * MEBIBYTE), N = (16 * MEBIBYTE) ;
2557
Byte_Value optimal_blocksize = benchmark_blocksize ;
2558
Sector offset_read = src_start ;
2559
Sector offset_write = dst_start ;
2561
//Handle situation where we need to perform the copy beginning
2562
// with the end of the partition and finishing with the start.
2563
if ( dst_start > src_start )
2565
offset_read += (src_length/src_sector_size) - (N/src_sector_size) ;
2566
/* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
2567
offset_write += ((src_length + (dst_sector_size - 1))/dst_sector_size) - (N/dst_sector_size) ;
2571
Byte_Value done = 0 ;
2573
double smallest_time = 1000000 ;
2574
bool succes = true ;
2576
//Benchmark copy times using different block sizes to determine optimal size
2578
llabs( done ) + N <= src_length &&
2579
benchmark_blocksize <= N )
2582
succes = copy_blocks( src_device,
2584
offset_read + (done / src_sector_size),
2585
offset_write + (done / dst_sector_size),
2587
benchmark_blocksize,
2588
operationdetail .get_last_child(),
2593
operationdetail .get_last_child() .get_last_child() .add_child( OperationDetail(
2594
String::ucompose( _("%1 seconds"), timer .elapsed() ), STATUS_NONE, FONT_ITALIC ) ) ;
2596
if ( timer .elapsed() <= smallest_time )
2598
smallest_time = timer .elapsed() ;
2599
optimal_blocksize = benchmark_blocksize ;
2601
benchmark_blocksize *= 2 ;
2603
if ( ( dst_start > src_start ) )
2610
operationdetail .get_last_child() .add_child( OperationDetail( String::ucompose(
2611
/*TO TRANSLATORS: looks like optimal block size is 1.00 MiB */
2612
_("optimal block size is %1"),
2613
Utils::format_size( optimal_blocksize, 1 ) ),
2616
if ( succes && llabs( done ) < src_length )
2617
succes = copy_blocks( src_device,
2619
src_start + ( dst_start > src_start ? 0 : (done / src_sector_size) ),
2620
dst_start + ( dst_start > src_start ? 0 : (done / dst_sector_size) ),
2621
src_length - llabs( done ),
2627
operationdetail .add_child( OperationDetail(
2628
String::ucompose( readonly ?
2629
/*TO TRANSLATORS: looks like 1.00 MiB (1048576 B) read */
2630
_("%1 (%2 B) read") :
2631
/*TO TRANSLATORS: looks like 1.00 MiB (1048576 B) copied */
2632
_("%1 (%2 B) copied"),
2633
Utils::format_size( total_done, 1 ), total_done ),
2638
void GParted_Core::rollback_transaction( const Partition & partition_src,
2639
const Partition & partition_dst,
2640
OperationDetail & operationdetail,
2641
Byte_Value total_done )
2643
if ( total_done > 0 )
2645
operationdetail .add_child( OperationDetail( _("roll back last transaction") ) ) ;
2647
//find out exactly which part of the file system was copied (and to where it was copied)..
2648
Partition temp_src = partition_src ;
2649
Partition temp_dst = partition_dst ;
2651
if ( partition_dst .sector_start > partition_src .sector_start )
2653
temp_src .sector_start = temp_src .sector_end - ( (total_done / temp_src .sector_size) - 1 ) ;
2654
temp_dst .sector_start = temp_dst .sector_end - ( (total_done / temp_dst .sector_size) - 1 ) ;
2658
temp_src .sector_end = temp_src .sector_start + ( (total_done / temp_src .sector_size) - 1 ) ;
2659
temp_dst .sector_end = temp_dst .sector_start + ( (total_done / temp_dst .sector_size) - 1 ) ;
2662
//and copy it back (NOTE the reversed dst and src)
2663
bool succes = copy_filesystem( temp_dst, temp_src, operationdetail .get_last_child() ) ;
2665
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2669
bool GParted_Core::check_repair_filesystem( const Partition & partition, OperationDetail & operationdetail )
2671
operationdetail .add_child( OperationDetail(
2673
/* TO TRANSLATORS: looks like check file system on /dev/sda5 for errors and (if possible) fix them */
2674
_("check file system on %1 for errors and (if possible) fix them"),
2675
partition .get_path() ) ) ) ;
2677
bool succes = false ;
2678
switch ( get_fs( partition .filesystem ) .check )
2680
case GParted::FS::NONE:
2681
operationdetail .get_last_child() .add_child(
2682
OperationDetail( _("checking is not available for this file system"),
2686
operationdetail .get_last_child() .set_status( STATUS_N_A ) ;
2690
case GParted::FS::GPARTED:
2692
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
2693
case GParted::FS::LIBPARTED:
2696
case GParted::FS::EXTERNAL:
2697
succes = set_proper_filesystem( partition .filesystem ) &&
2698
p_filesystem ->check_repair( partition, operationdetail .get_last_child() ) ;
2706
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2710
bool GParted_Core::set_partition_type( const Partition & partition, OperationDetail & operationdetail )
2712
operationdetail .add_child( OperationDetail(
2713
String::ucompose( _("set partition type on %1"), partition .get_path() ) ) ) ;
2715
bool return_value = false ;
2717
if ( open_device_and_disk( partition .device_path ) )
2719
PedFileSystemType * fs_type =
2720
ped_file_system_type_get( Utils::get_filesystem_string( partition .filesystem ) .c_str() ) ;
2722
//If not found, and FS is linux-swap, then try linux-swap(v1)
2723
if ( ! fs_type && Utils::get_filesystem_string( partition .filesystem ) == "linux-swap" )
2724
fs_type = ped_file_system_type_get( "linux-swap(v1)" ) ;
2726
//If not found, and FS is linux-swap, then try linux-swap(new)
2727
if ( ! fs_type && Utils::get_filesystem_string( partition .filesystem ) == "linux-swap" )
2728
fs_type = ped_file_system_type_get( "linux-swap(new)" ) ;
2730
//default is Linux (83)
2732
fs_type = ped_file_system_type_get( "ext2" ) ;
2736
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
2738
if ( lp_partition &&
2739
ped_partition_set_system( lp_partition, fs_type ) &&
2742
operationdetail .get_last_child() .add_child(
2743
OperationDetail( String::ucompose( _("new partition type: %1"),
2744
lp_partition ->fs_type ->name ),
2748
return_value = true ;
2752
close_device_and_disk() ;
2755
operationdetail .get_last_child() .set_status( return_value ? STATUS_SUCCES : STATUS_ERROR ) ;
2756
return return_value ;
2759
void GParted_Core::set_progress_info( Byte_Value total,
2761
const Glib::Timer & timer,
2762
OperationDetail & operationdetail,
2765
operationdetail .fraction = done / static_cast<double>( total ) ;
2767
std::time_t time_remaining = Utils::round( (total - done) / ( done / timer .elapsed() ) ) ;
2769
operationdetail .progress_text =
2770
String::ucompose( readonly ?
2771
/*TO TRANSLATORS: looks like 1.00 MiB of 16.00 MiB read (00:01:59 remaining) */
2772
_("%1 of %2 read (%3 remaining)") :
2773
/*TO TRANSLATORS: looks like 1.00 MiB of 16.00 MiB copied (00:01:59 remaining) */
2774
_("%1 of %2 copied (%3 remaining)"),
2775
Utils::format_size( done, 1 ),
2776
Utils::format_size( total,1 ),
2777
Utils::format_time( time_remaining) ) ;
2779
operationdetail .set_description(
2780
String::ucompose( readonly ?
2781
/*TO TRANSLATORS: looks like 1.00 MiB of 16.00 MiB read */
2782
_("%1 of %2 read") :
2783
/*TO TRANSLATORS: looks like 1.00 MiB of 16.00 MiB copied */
2784
_("%1 of %2 copied"),
2785
Utils::format_size( done, 1 ), Utils::format_size( total, 1 ) ),
2789
bool GParted_Core::copy_blocks( const Glib::ustring & src_device,
2790
const Glib::ustring & dst_device,
2794
Byte_Value blocksize,
2795
OperationDetail & operationdetail,
2797
Byte_Value & total_done )
2799
if ( blocksize > length )
2800
blocksize = length ;
2803
operationdetail .add_child( OperationDetail(
2804
/*TO TRANSLATORS: looks like read 16.00 MiB using a block size of 1.00 MiB */
2805
String::ucompose( _("read %1 using a block size of %2"), Utils::format_size( length, 1 ),
2806
Utils::format_size( blocksize, 1 ) ) ) ) ;
2808
operationdetail .add_child( OperationDetail(
2809
/*TO TRANSLATORS: looks like copy 16.00 MiB using a block size of 1.00 MiB */
2810
String::ucompose( _("copy %1 using a block size of %2"), Utils::format_size( length, 1 ),
2811
Utils::format_size( blocksize, 1 ) ) ) ) ;
2813
Byte_Value done = length % blocksize ;
2815
bool succes = false ;
2816
PedDevice *lp_device_src = ped_device_get( src_device .c_str() );
2817
PedDevice *lp_device_dst = src_device != dst_device ? ped_device_get( dst_device .c_str() ) : lp_device_src ;
2819
if ( lp_device_src && lp_device_dst && ped_device_open( lp_device_src ) && ped_device_open( lp_device_dst ) )
2821
Byte_Value src_sector_size = lp_device_src ->sector_size ;
2822
Byte_Value dst_sector_size = lp_device_dst ->sector_size ;
2824
//Handle situation where we need to perform the copy beginning
2825
// with the end of the partition and finishing with the start.
2826
if ( dst_start > src_start )
2828
blocksize -= 2*blocksize ;
2830
src_start += ( (length / src_sector_size) - 1 ) ;
2831
/* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
2832
dst_start += ( ((length + (dst_sector_size - 1))/ dst_sector_size) - 1 ) ;
2835
Glib::ustring error_message ;
2836
buf = static_cast<char *>( malloc( llabs( blocksize ) ) ) ;
2839
ped_device_sync( lp_device_dst ) ;
2843
succes = copy_block( lp_device_src,
2853
//add an empty sub which we will constantly update in the loop
2854
operationdetail .get_last_child() .add_child( OperationDetail( "", STATUS_NONE ) ) ;
2856
Glib::Timer timer_progress_timeout, timer_total ;
2857
while( succes && llabs( done ) < length )
2859
succes = copy_block( lp_device_src,
2861
src_start + (done / src_sector_size),
2862
dst_start + (done / dst_sector_size),
2869
if ( timer_progress_timeout .elapsed() >= 0.5 )
2871
set_progress_info( length,
2872
llabs( done + blocksize ),
2874
operationdetail .get_last_child() .get_last_child(),
2877
timer_progress_timeout .reset() ;
2880
//set progress bar current info on completion
2881
set_progress_info( length,
2884
operationdetail .get_last_child() .get_last_child(),
2890
error_message = Glib::strerror( errno ) ;
2892
//reset fraction to -1 to make room for a new one (or a pulsebar)
2893
operationdetail .get_last_child() .get_last_child() .fraction = -1 ;
2896
operationdetail .get_last_child() .get_last_child() .set_description(
2897
String::ucompose( readonly ?
2898
/*TO TRANSLATORS: looks like 1.00 MiB of 16.00 MiB read */
2899
_("%1 of %2 read") :
2900
/*TO TRANSLATORS: looks like 1.00 MiB of 16.00 MiB copied */
2901
_("%1 of %2 copied"),
2902
Utils::format_size( llabs( done ), 1 ),
2903
Utils::format_size( length, 1 ) ),
2906
if ( ! succes && ! error_message .empty() )
2907
operationdetail .get_last_child() .add_child(
2908
OperationDetail( error_message, STATUS_NONE, FONT_ITALIC ) ) ;
2910
total_done += llabs( done ) ;
2912
//close and destroy the devices..
2913
ped_device_close( lp_device_src ) ;
2914
ped_device_destroy( lp_device_src ) ;
2916
if ( src_device != dst_device )
2918
ped_device_close( lp_device_dst ) ;
2919
ped_device_destroy( lp_device_dst ) ;
2923
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2927
bool GParted_Core::copy_block( PedDevice * lp_device_src,
2928
PedDevice * lp_device_dst,
2931
Byte_Value block_length,
2932
Glib::ustring & error_message,
2935
Byte_Value sector_size_src = lp_device_src ->sector_size ;
2936
Byte_Value sector_size_dst = lp_device_dst ->sector_size ;
2938
//Handle case where src and dst sector sizes are different.
2939
// E.g., 5 sectors x 512 bytes/sector = ??? 2048 byte sectors
2940
Sector num_blocks_src = (llabs(block_length) + (sector_size_src - 1) ) / sector_size_src ;
2941
Sector num_blocks_dst = (llabs(block_length) + (sector_size_dst - 1) ) / sector_size_dst ;
2943
//Handle situation where we are performing copy operation beginning
2944
// with the end of the partition and finishing with the start.
2945
if ( block_length < 0 )
2947
block_length = llabs( block_length ) ;
2948
offset_src -= ( (block_length / sector_size_src) - 1 ) ;
2949
/* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
2950
offset_dst -= ( ( (block_length + (sector_size_dst - 1)) / sector_size_dst) - 1 ) ;
2953
if ( block_length != 0 )
2955
if ( ped_device_read( lp_device_src, buf, offset_src, num_blocks_src ) )
2957
if ( readonly || ped_device_write( lp_device_dst, buf, offset_dst, num_blocks_dst ) )
2960
error_message = String::ucompose( _("Error while writing block at sector %1"), offset_dst ) ;
2963
error_message = String::ucompose( _("Error while reading block at sector %1"), offset_src ) ;
2969
bool GParted_Core::calibrate_partition( Partition & partition, OperationDetail & operationdetail )
2971
if ( partition .type == TYPE_PRIMARY || partition .type == TYPE_LOGICAL || partition .type == TYPE_EXTENDED )
2973
operationdetail .add_child( OperationDetail( String::ucompose( _("calibrate %1"), partition .get_path() ) ) ) ;
2975
bool succes = false ;
2976
if ( open_device_and_disk( partition .device_path ) )
2978
if ( partition .type == GParted::TYPE_EXTENDED )
2979
lp_partition = ped_disk_extended_partition( lp_disk ) ;
2981
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
2983
if ( lp_partition )//FIXME: add check to see if lp_partition ->type matches partition .type..
2985
partition .add_path( get_partition_path( lp_partition ) ) ;
2987
partition .sector_start = lp_partition ->geom .start ;
2988
partition .sector_end = lp_partition ->geom .end ;
2990
operationdetail .get_last_child() .add_child(
2992
String::ucompose( _("path: %1"), partition .get_path() ) + "\n" +
2993
String::ucompose( _("start: %1"), partition .sector_start ) + "\n" +
2994
String::ucompose( _("end: %1"), partition .sector_end ) + "\n" +
2995
String::ucompose( _("size: %1 (%2)"),
2996
partition .get_sector_length(),
2997
Utils::format_size( partition .get_sector_length(), partition .sector_size ) ),
3003
close_device_and_disk() ;
3006
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
3009
else //nothing to calibrate...
3013
bool GParted_Core::calculate_exact_geom( const Partition & partition_old,
3014
Partition & partition_new,
3015
OperationDetail & operationdetail )
3017
operationdetail .add_child( OperationDetail(
3018
String::ucompose( _("calculate new size and position of %1"), partition_new .get_path() ) ) ) ;
3020
operationdetail .get_last_child() .add_child(
3022
String::ucompose( _("requested start: %1"), partition_new .sector_start ) + "\n" +
3023
String::ucompose( _("requested end: %1"), partition_new .sector_end ) + "\n" +
3024
String::ucompose( _("requested size: %1 (%2)"),
3025
partition_new .get_sector_length(),
3026
Utils::format_size( partition_new .get_sector_length(), partition_new .sector_size ) ),
3030
bool succes = false ;
3031
if ( open_device_and_disk( partition_old .device_path ) )
3033
lp_partition = NULL ;
3035
if ( partition_old .type == GParted::TYPE_EXTENDED )
3036
lp_partition = ped_disk_extended_partition( lp_disk ) ;
3038
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition_old .get_sector() ) ;
3042
PedConstraint *constraint = NULL ;
3043
constraint = ped_constraint_any( lp_device ) ;
3047
//FIXME: if we insert a weird partitionnew geom here (e.g. start > end)
3048
//ped_disk_set_partition_geom() will still return true (althoug an lp exception is written
3049
//to stdout.. see if this also affect create_partition and resize_move_partition
3050
//sended a patch to fix this to libparted list. will probably be in 1.7.2
3051
if ( ped_disk_set_partition_geom( lp_disk,
3054
partition_new .sector_start,
3055
partition_new .sector_end ) )
3057
partition_new .sector_start = lp_partition ->geom .start ;
3058
partition_new .sector_end = lp_partition ->geom .end ;
3062
ped_constraint_destroy( constraint );
3066
close_device_and_disk() ;
3071
operationdetail .get_last_child() .add_child(
3073
String::ucompose( _("new start: %1"), partition_new .sector_start ) + "\n" +
3074
String::ucompose( _("new end: %1"), partition_new .sector_end ) + "\n" +
3075
String::ucompose( _("new size: %1 (%2)"),
3076
partition_new .get_sector_length(),
3077
Utils::format_size( partition_new .get_sector_length(), partition_new .sector_size ) ),
3081
#ifndef USE_LIBPARTED_DMRAID
3082
//Update dev mapper entry if partition is dmraid.
3084
if ( succes && dmraid .is_dmraid_device( partition_new .device_path ) )
3086
//Open disk handle before and close after to prevent application crash.
3087
if ( open_device_and_disk( partition_new .device_path ) )
3089
succes = dmraid .update_dev_map_entry( partition_new, operationdetail .get_last_child() ) ;
3090
close_device_and_disk() ;
3096
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
3100
bool GParted_Core::set_proper_filesystem( const FILESYSTEM & filesystem )
3102
p_filesystem = get_filesystem_object( filesystem ) ;
3104
return p_filesystem ;
3107
FileSystem * GParted_Core::get_filesystem_object( const FILESYSTEM & filesystem )
3109
if ( FILESYSTEM_MAP .count( filesystem ) )
3110
return FILESYSTEM_MAP[ filesystem ] ;
3115
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
3116
bool GParted_Core::erase_filesystem_signatures( const Partition & partition )
3118
bool return_value = false ;
3120
if ( open_device_and_disk( partition .device_path ) )
3122
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
3124
if ( lp_partition && ped_file_system_clobber( & lp_partition ->geom ) )
3126
//file systems not yet supported by libparted
3127
if ( ped_device_open( lp_device ) )
3129
//reiser4 stores "ReIsEr4" at sector 128 with a sector size of 512 bytes
3130
// FIXME writing block of partially uninitialized bytes (security/privacy)
3131
return_value = ped_geometry_write( & lp_partition ->geom, "0000000", (65536 / lp_device ->sector_size), 1 ) ;
3133
ped_device_close( lp_device ) ;
3137
close_device_and_disk() ;
3140
return return_value ;
3144
bool GParted_Core::update_bootsector( const Partition & partition, OperationDetail & operationdetail )
3146
//only for ntfs atm...
3147
//FIXME: this should probably be done in the fs classes...
3148
if ( partition .filesystem == FS_NTFS )
3150
//The NTFS file system stores a value in the boot record called the
3151
// Number of Hidden Sectors. This value must match the partition start
3152
// sector number in order for Windows to boot from the file system.
3153
// For more details, refer to the NTFS Volume Boot Record at:
3154
// http://www.geocities.com/thestarman3/asm/mbr/NTFSBR.htm
3156
operationdetail .add_child( OperationDetail(
3157
/*TO TRANSLATORS: update boot sector of ntfs file system on /dev/sdd1 */
3158
String::ucompose( _("update boot sector of %1 file system on %2"),
3159
Utils::get_filesystem_string( partition .filesystem ),
3160
partition .get_path() ) ) ) ;
3162
//convert start sector to hex string
3163
std::stringstream ss ;
3164
ss << std::hex << partition .sector_start ;
3165
Glib::ustring hex = ss .str() ;
3167
//fill with zeros and reverse...
3168
hex .insert( 0, 8 - hex .length(), '0' ) ;
3169
Glib::ustring reversed_hex ;
3170
for ( int t = 6 ; t >= 0 ; t -=2 )
3171
reversed_hex .append( hex .substr( t, 2 ) ) ;
3173
//convert reversed hex codes into ascii characters
3175
for ( unsigned int k = 0; (k < 4 && k < (reversed_hex .length() / 2)); k++ )
3177
Glib::ustring tmp_hex = "0x" + reversed_hex .substr( k * 2, 2 ) ;
3178
buf[k] = (char)( std::strtol( tmp_hex .c_str(), NULL, 16 ) ) ;
3181
//write new Number of Hidden Sectors value into NTFS boot sector at offset 0x1C
3182
Glib::ustring error_message = "" ;
3183
std::ofstream dev_file ;
3184
dev_file .open( partition .get_path() .c_str(), std::ios::out | std::ios::binary ) ;
3185
if ( dev_file .is_open() )
3187
dev_file .seekp( 0x1C ) ;
3188
if ( dev_file .good() )
3190
dev_file .write( buf, 4 ) ;
3191
if ( dev_file .bad() )
3193
/*TO TRANSLATORS: looks like Error trying to write to boot sector in /dev/sdd1 */
3194
error_message = String::ucompose( _("Error trying to write to boot sector in %1"), partition .get_path() ) ;
3199
/*TO TRANSLATORS: looks like Error trying to seek to position 0x1C in /dev/sdd1 */
3200
error_message = String::ucompose( _("Error trying to seek to position 0x1c in %1"), partition .get_path() ) ;
3202
dev_file .close( ) ;
3206
/*TO TRANSLATORS: looks like Error trying to open /dev/sdd1 */
3207
error_message = String::ucompose( _("Error trying to open %1"), partition .get_path() ) ;
3210
//append error messages if any found
3211
bool succes = true ;
3212
if ( ! error_message .empty() )
3215
error_message += "\n" ;
3216
/*TO TRANSLATORS: looks like Failed to set the number of hidden sectors to 05ab4f00 in the ntfs boot record. */
3217
error_message += String::ucompose( _("Failed to set the number of hidden sectors to %1 in the NTFS boot record."), reversed_hex ) ;
3218
error_message += "\n" ;
3219
error_message += String::ucompose( _("You might try the following command to correct the problem:"), reversed_hex ) ;
3220
error_message += "\n" ;
3221
error_message += String::ucompose( "echo %1 | xxd -r -p | dd conv=notrunc of=%2 bs=1 seek=28", reversed_hex, partition .get_path() ) ;
3222
operationdetail .get_last_child() .add_child( OperationDetail( error_message, STATUS_NONE, FONT_ITALIC ) ) ;
3225
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
3232
bool GParted_Core::open_device( const Glib::ustring & device_path )
3234
lp_device = ped_device_get( device_path .c_str() );
3239
bool GParted_Core::open_device_and_disk( const Glib::ustring & device_path, bool strict )
3244
if ( open_device( device_path ) )
3246
lp_disk = ped_disk_new( lp_device );
3248
//if ! disk and writeable it's probably a HD without disklabel.
3249
//We return true here and deal with them in GParted_Core::get_devices
3250
if ( lp_disk || ( ! strict && ! lp_device ->read_only ) )
3253
close_device_and_disk() ;
3259
void GParted_Core::close_disk()
3262
ped_disk_destroy( lp_disk ) ;
3267
void GParted_Core::close_device_and_disk()
3272
ped_device_destroy( lp_device ) ;
3277
bool GParted_Core::commit()
3279
bool succes = ped_disk_commit_to_dev( lp_disk ) ;
3281
succes = commit_to_os( 10 ) && succes ;
3286
bool GParted_Core::commit_to_os( std::time_t timeout )
3289
#ifndef USE_LIBPARTED_DMRAID
3291
if ( dmraid .is_dmraid_device( lp_disk ->dev ->path ) )
3296
succes = ped_disk_commit_to_os( lp_disk ) ;
3297
#ifndef HAVE_LIBPARTED_2_2_0_PLUS
3298
//Work around to try to alleviate problems caused by
3299
// bug #604298 - Failure to inform kernel of partition changes
3300
// If not successful the first time, try one more time.
3304
succes = ped_disk_commit_to_os( lp_disk ) ;
3307
#ifndef USE_LIBPARTED_DMRAID
3311
settle_device( timeout ) ;
3316
void GParted_Core::settle_device( std::time_t timeout )
3318
if ( ! Glib::find_program_in_path( "udevsettle" ) .empty() )
3319
Utils::execute_command( "udevsettle --timeout=" + Utils::num_to_str( timeout ) ) ;
3320
else if ( ! Glib::find_program_in_path( "udevadm" ) .empty() )
3321
Utils::execute_command( "udevadm settle --timeout=" + Utils::num_to_str( timeout ) ) ;
3326
class PedExceptionMsg : public Gtk::MessageDialog
3329
PedExceptionMsg( PedException &e ) : MessageDialog( Glib::ustring(e.message), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_NONE, true )
3333
case PED_EXCEPTION_WARNING:
3334
set_title( _("Libparted Warning") );
3335
property_message_type() = Gtk::MESSAGE_WARNING;
3337
case PED_EXCEPTION_INFORMATION:
3338
set_title( _("Libparted Information") );
3339
property_message_type() = Gtk::MESSAGE_INFO;
3341
case PED_EXCEPTION_ERROR:
3342
set_title( _("Libparted Error") );
3344
set_title( _("Libparted Bug Found!") );
3346
if (e.options & PED_EXCEPTION_FIX)
3347
add_button( _("Fix"), PED_EXCEPTION_FIX );
3348
if (e.options & PED_EXCEPTION_YES)
3349
add_button( _("Yes"), PED_EXCEPTION_YES );
3350
if (e.options & PED_EXCEPTION_OK)
3351
add_button( _("Ok"), PED_EXCEPTION_OK );
3352
if (e.options & PED_EXCEPTION_RETRY)
3353
add_button( _("Retry"), PED_EXCEPTION_RETRY );
3354
if (e.options & PED_EXCEPTION_NO)
3355
add_button( _("No"), PED_EXCEPTION_NO );
3356
if (e.options & PED_EXCEPTION_CANCEL)
3357
add_button( _("Cancel"), PED_EXCEPTION_CANCEL );
3358
if (e.options & PED_EXCEPTION_IGNORE)
3359
add_button( _("Ignore"), PED_EXCEPTION_IGNORE );
3363
PedExceptionOption GParted_Core::ped_exception_handler( PedException * e )
3365
PedExceptionOption ret = PED_EXCEPTION_UNHANDLED;
3366
std::cout << e ->message << std::endl ;
3368
libparted_messages .push_back( e->message ) ;
3371
for( char c = 0; c < 10; c++ )
3372
if( e->options & (1 << c) ) {
3376
// if only one option was given, choose it without popup
3377
if( optcount == 1 && e->type != PED_EXCEPTION_BUG && e->type != PED_EXCEPTION_FATAL )
3378
return (PedExceptionOption)opt;
3379
if (Glib::Thread::self() != GParted_Core::mainthread)
3380
gdk_threads_enter();
3381
PedExceptionMsg msg( *e );
3383
ret = (PedExceptionOption)msg.run();
3384
if (Glib::Thread::self() != GParted_Core::mainthread)
3385
gdk_threads_leave();
3387
ret = PED_EXCEPTION_UNHANDLED;
3391
GParted_Core::~GParted_Core()
3393
delete p_filesystem;
3396
Glib::Thread *GParted_Core::mainthread;