1
/* Copyright (C) 2004 Bart 'plors' Hakvoort
2
* Copyright (C) 2008, 2009, 2010, 2011 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/OperationCopy.h"
25
#include "../include/OperationCreate.h"
26
#include "../include/OperationDelete.h"
27
#include "../include/OperationFormat.h"
28
#include "../include/OperationResizeMove.h"
29
#include "../include/OperationLabelPartition.h"
30
#include "../include/Proc_Partitions_Info.h"
32
#include "../include/btrfs.h"
33
#include "../include/exfat.h"
34
#include "../include/ext2.h"
35
#include "../include/ext3.h"
36
#include "../include/ext4.h"
37
#include "../include/fat16.h"
38
#include "../include/fat32.h"
39
#include "../include/linux_swap.h"
40
#include "../include/reiserfs.h"
41
#include "../include/ntfs.h"
42
#include "../include/xfs.h"
43
#include "../include/jfs.h"
44
#include "../include/hfs.h"
45
#include "../include/hfsplus.h"
46
#include "../include/reiser4.h"
47
#include "../include/ufs.h"
51
#include <sys/statvfs.h>
52
#include <sys/types.h>
58
std::vector<Glib::ustring> libparted_messages ; //see ped_exception_handler()
63
GParted_Core::GParted_Core()
69
thread_status_message = "" ;
71
ped_exception_set_handler( ped_exception_handler ) ;
74
for ( PedPartitionFlag flag = ped_partition_flag_next( static_cast<PedPartitionFlag>( NULL ) ) ;
76
flag = ped_partition_flag_next( flag ) )
77
flags .push_back( flag ) ;
79
//throw libpartedversion to the stdout to see which version is actually used.
80
std::cout << "======================" << std::endl ;
81
std::cout << "libparted : " << ped_get_version() << std::endl ;
82
std::cout << "======================" << std::endl ;
84
//initialize file system list
85
find_supported_filesystems() ;
88
void GParted_Core::find_supported_filesystems()
90
FILESYSTEMS .clear() ;
95
FILESYSTEMS .push_back( fs_btrfs .get_filesystem_support() ) ;
98
FILESYSTEMS .push_back( fs_exfat .get_filesystem_support() ) ;
101
FILESYSTEMS .push_back( fs_ext2 .get_filesystem_support() ) ;
104
FILESYSTEMS .push_back( fs_ext3 .get_filesystem_support() ) ;
107
FILESYSTEMS .push_back( fs_ext4 .get_filesystem_support() ) ;
110
FILESYSTEMS .push_back( fs_fat16 .get_filesystem_support() ) ;
113
FILESYSTEMS .push_back( fs_fat32 .get_filesystem_support() ) ;
116
FILESYSTEMS .push_back( fs_hfs .get_filesystem_support() ) ;
119
FILESYSTEMS .push_back( fs_hfsplus .get_filesystem_support() ) ;
122
FILESYSTEMS .push_back( fs_jfs .get_filesystem_support() ) ;
124
linux_swap fs_linux_swap;
125
FILESYSTEMS .push_back( fs_linux_swap .get_filesystem_support() ) ;
128
FILESYSTEMS .push_back( fs_ntfs .get_filesystem_support() ) ;
131
FILESYSTEMS .push_back( fs_reiser4 .get_filesystem_support() ) ;
133
reiserfs fs_reiserfs;
134
FILESYSTEMS .push_back( fs_reiserfs .get_filesystem_support() ) ;
137
FILESYSTEMS .push_back( fs_ufs .get_filesystem_support() ) ;
140
FILESYSTEMS .push_back( fs_xfs .get_filesystem_support() ) ;
142
//lvm2 physical volume -- not a file system
143
fs_notsupp .filesystem = GParted::FS_LVM2 ;
144
FILESYSTEMS .push_back( fs_notsupp ) ;
146
//luks encryption-- not a file system
147
fs_notsupp .filesystem = GParted::FS_LUKS ;
148
FILESYSTEMS .push_back( fs_notsupp ) ;
150
//unknown file system (default when no match is found)
151
fs_notsupp .filesystem = GParted::FS_UNKNOWN ;
152
FILESYSTEMS .push_back( fs_notsupp ) ;
155
void GParted_Core::set_user_devices( const std::vector<Glib::ustring> & user_devices )
157
this ->device_paths = user_devices ;
158
this ->probe_devices = ! user_devices .size() ;
161
void GParted_Core::set_devices( std::vector<Device> & devices )
165
Proc_Partitions_Info pp_info( true ) ; //Refresh cache of proc partition information
166
FS_Info fs_info( true ) ; //Refresh cache of file system information
167
DMRaid dmraid( true ) ; //Refresh cache of dmraid device information
168
SWRaid swraid( true ) ; //Refresh cache of swraid device information
172
//only probe if no devices were specified as arguments..
175
device_paths .clear() ;
177
//FIXME: When libparted bug 194 is fixed, remove code to read:
179
// This was a problem with no floppy drive yet BIOS indicated one existed.
180
// http://parted.alioth.debian.org/cgi-bin/trac.cgi/ticket/194
182
//try to find all available devices if devices exist in /proc/partitions
183
std::vector<Glib::ustring> temp_devices = pp_info .get_device_paths() ;
184
if ( ! temp_devices .empty() )
186
//Try to find all devices in /proc/partitions
187
for (unsigned int k=0; k < temp_devices .size(); k++)
189
/*TO TRANSLATORS: looks like Scanning /dev/sda */
190
set_thread_status_message( String::ucompose ( _("Scanning %1"), temp_devices[ k ] ) ) ;
191
ped_device_get( temp_devices[ k ] .c_str() ) ;
194
//Try to find all swraid devices
195
if (swraid .is_swraid_supported() ) {
196
std::vector<Glib::ustring> swraid_devices ;
197
swraid .get_devices( swraid_devices ) ;
198
for ( unsigned int k=0; k < swraid_devices .size(); k++ ) {
199
set_thread_status_message( String::ucompose ( _("Scanning %1"), swraid_devices[k] ) ) ;
200
ped_device_get( swraid_devices[k] .c_str() ) ;
204
//Try to find all dmraid devices
205
if (dmraid .is_dmraid_supported() ) {
206
std::vector<Glib::ustring> dmraid_devices ;
207
dmraid .get_devices( dmraid_devices ) ;
208
for ( unsigned int k=0; k < dmraid_devices .size(); k++ ) {
209
set_thread_status_message( String::ucompose ( _("Scanning %1"), dmraid_devices[k] ) ) ;
210
#ifndef USE_LIBPARTED_DMRAID
211
dmraid .create_dev_map_entries( dmraid_devices[k] ) ;
214
ped_device_get( dmraid_devices[k] .c_str() ) ;
220
//No devices found in /proc/partitions so use libparted to probe devices
221
ped_device_probe_all();
224
lp_device = ped_device_get_next( NULL );
227
//only add this device if we can read the first sector (which means it's a real device)
228
char * buf = static_cast<char *>( malloc( lp_device ->sector_size ) ) ;
231
/*TO TRANSLATORS: looks like Confirming /dev/sda */
232
set_thread_status_message( String::ucompose ( _("Confirming %1"), lp_device ->path ) ) ;
233
if ( ped_device_open( lp_device ) )
235
#ifdef HAVE_LIBPARTED_2_2_0_PLUS
236
//Devices with sector sizes of 512 bytes and higher are supported
237
if ( ped_device_read( lp_device, buf, 0, 1 ) )
238
device_paths .push_back( lp_device ->path ) ;
240
//Only devices with sector sizes of 512 bytes are well supported
241
if ( lp_device ->sector_size != 512 )
243
/*TO TRANSLATORS: looks like Ignoring device /dev/sde with logical sector size of 2048 bytes. */
244
Glib::ustring msg = String::ucompose ( _("Ignoring device %1 with logical sector size of %2 bytes."), lp_device ->path, lp_device ->sector_size ) ;
246
msg += _("GParted requires libparted version 2.2 or higher to support devices with sector sizes larger than 512 bytes.") ;
247
std::cout << msg << std::endl << std::endl ;
251
if ( ped_device_read( lp_device, buf, 0, 1 ) )
252
device_paths .push_back( lp_device ->path ) ;
255
ped_device_close( lp_device ) ;
259
lp_device = ped_device_get_next( lp_device ) ;
261
close_device_and_disk() ;
263
std::sort( device_paths .begin(), device_paths .end() ) ;
265
#ifndef USE_LIBPARTED_DMRAID
268
//Device paths were passed in on the command line.
270
//Ensure that dmraid device entries are created
271
for ( unsigned int t = 0 ; t < device_paths .size() ; t++ )
273
if ( dmraid .is_dmraid_supported() &&
274
dmraid .is_dmraid_device( device_paths[t] ) )
276
dmraid .create_dev_map_entries( dmraid .get_dmraid_name( device_paths [t] ) ) ;
282
for ( unsigned int t = 0 ; t < device_paths .size() ; t++ )
284
/*TO TRANSLATORS: looks like Searching /dev/sda partitions */
285
set_thread_status_message( String::ucompose ( _("Searching %1 partitions"), device_paths[ t ] ) ) ;
286
if ( open_device_and_disk( device_paths[ t ], false ) )
288
temp_device .Reset() ;
291
temp_device .add_path( device_paths[ t ] ) ;
292
temp_device .add_paths( pp_info .get_alternate_paths( temp_device .get_path() ) ) ;
294
temp_device .model = lp_device ->model ;
295
temp_device .length = lp_device ->length ;
296
temp_device .sector_size = lp_device ->sector_size ;
297
temp_device .heads = lp_device ->bios_geom .heads ;
298
temp_device .sectors = lp_device ->bios_geom .sectors ;
299
temp_device .cylinders = lp_device ->bios_geom .cylinders ;
300
temp_device .cylsize = temp_device .heads * temp_device .sectors ;
302
//make sure cylsize is at least 1 MiB
303
if ( temp_device .cylsize < (MEBIBYTE / temp_device .sector_size) )
304
temp_device .cylsize = (MEBIBYTE / temp_device .sector_size) ;
309
temp_device .disktype = lp_disk ->type ->name ;
310
temp_device .max_prims = ped_disk_get_max_primary_partition_count( lp_disk ) ;
312
set_device_partitions( temp_device ) ;
313
set_mountpoints( temp_device .partitions ) ;
314
set_used_sectors( temp_device .partitions ) ;
316
if ( temp_device .highest_busy )
318
temp_device .readonly = ! commit_to_os( 1 ) ;
319
//Clear libparted messages. Typically these are:
320
// The kernel was unable to re-read the partition table...
321
libparted_messages .clear() ;
324
//harddisk without disklabel
327
temp_device .disktype =
328
/* TO TRANSLATORS: unrecognized
329
* means that the partition table for this
330
* disk device is unknown or not recognized.
333
temp_device .max_prims = -1 ;
335
Partition partition_temp ;
336
partition_temp .Set_Unallocated( temp_device .get_path(),
338
temp_device .length - 1,
339
temp_device .sector_size,
341
//Place libparted messages in this unallocated partition
342
partition_temp .messages .insert( partition_temp .messages .end(),
343
libparted_messages. begin(),
344
libparted_messages .end() ) ;
345
libparted_messages .clear() ;
346
temp_device .partitions .push_back( partition_temp );
349
devices .push_back( temp_device ) ;
351
close_device_and_disk() ;
355
//clear leftover information...
356
//NOTE that we cannot clear mountinfo since it might be needed in get_all_mountpoints()
357
set_thread_status_message("") ;
358
fstab_info .clear() ;
361
// runs gpart on the specified parameter
362
void GParted_Core::guess_partition_table(const Device & device, Glib::ustring &buff)
364
int pid, stdoutput, stderror;
365
std::vector<std::string> argvproc, envpproc;
368
//Get the char string of the sector_size
369
std::ostringstream ssIn;
370
ssIn << device.sector_size;
371
Glib::ustring str_ssize = ssIn.str();
373
//Build the command line
374
argvproc.push_back("gpart");
375
argvproc.push_back(device.get_path());
376
argvproc.push_back("-s");
377
argvproc.push_back(str_ssize);
379
envpproc .push_back( "LC_ALL=C" ) ;
380
envpproc .push_back( "PATH=" + Glib::getenv( "PATH" ) ) ;
382
Glib::spawn_async_with_pipes(Glib::get_current_dir(), argvproc,
383
envpproc, Glib::SPAWN_SEARCH_PATH, sigc::slot<void>(),
384
&pid, NULL, &stdoutput, &stderror);
386
this->iocOutput=Glib::IOChannel::create_from_fd(stdoutput);
388
while(this->iocOutput->read(tmp)==Glib::IO_STATUS_NORMAL)
392
this->iocOutput->close();
397
void GParted_Core::set_thread_status_message( Glib::ustring msg )
399
//Remember to clear status message when finished with thread.
400
thread_status_message = msg ;
403
Glib::ustring GParted_Core::get_thread_status_message( )
405
return thread_status_message ;
408
bool GParted_Core::snap_to_cylinder( const Device & device, Partition & partition, Glib::ustring & error )
412
//Determine if partition size is less than half a disk cylinder
413
bool less_than_half_cylinder = false;
414
if ( ( partition .sector_end - partition .sector_start ) < ( device .cylsize / 2 ) )
415
less_than_half_cylinder = true;
417
if ( partition.type == TYPE_LOGICAL ||
418
partition.sector_start == device .sectors
421
//Must account the relative offset between:
422
// (A) the Extended Boot Record sector and the next track of the
423
// logical partition (usually 63 sectors), and
424
// (B) the Master Boot Record sector and the next track of the first
426
diff = (partition .sector_start - device .sectors) % device .cylsize ;
428
else if ( partition.sector_start == 34 )
430
// (C) the GUID Partition Table (GPT) and the start of the data
431
// partition at sector 34
432
diff = (partition .sector_start - 34 ) % device .cylsize ;
436
diff = partition .sector_start % device .cylsize ;
438
if ( diff && ! partition .strict_start )
440
if ( diff < ( device .cylsize / 2 ) || less_than_half_cylinder )
441
partition .sector_start -= diff ;
443
partition .sector_start += (device .cylsize - diff ) ;
446
diff = (partition .sector_end +1) % device .cylsize ;
449
if ( diff < ( device .cylsize / 2 ) && ! less_than_half_cylinder )
450
partition .sector_end -= diff ;
452
partition .sector_end += (device .cylsize - diff ) ;
458
bool GParted_Core::snap_to_mebibyte( const Device & device, Partition & partition, Glib::ustring & error )
461
if ( partition .sector_start < 2 || partition .type == TYPE_LOGICAL )
463
//Must account the relative offset between:
464
// (A) the Master Boot Record sector and the first primary/extended partition, and
465
// (B) the Extended Boot Record sector and the logical partition
467
//If strict_start is set then do not adjust sector start.
468
//If this partition is not simply queued for a reformat then
469
// add space minimum to force alignment to next mebibyte.
470
if ( (! partition .strict_start)
471
&& (partition .free_space_before == 0)
472
&& ( partition .status != STAT_FORMATTED)
475
//Unless specifically told otherwise, the Linux kernel considers extended
476
// boot records to be two sectors long, in order to "leave room for LILO".
477
partition .sector_start += 2 ;
482
diff = Sector(partition .sector_start % ( MEBIBYTE / partition .sector_size ));
483
if ( diff && ( (! partition .strict_start)
484
|| ( partition .strict_start
485
&& ( partition .status == STAT_NEW
486
|| partition .status == STAT_COPY
491
partition .sector_start += ( (MEBIBYTE / partition .sector_size) - diff) ;
493
//If this is a logical partition not at end of drive then check to see if space is
494
// required for a following logical partition Extended Boot Record
495
if ( partition .type == TYPE_LOGICAL )
497
//Locate the extended partition that contains the logical partitions.
498
int index_extended = -1 ;
499
for ( unsigned int t = 0 ; t < device .partitions .size() ; t++ )
501
if ( device .partitions[ t ] .type == TYPE_EXTENDED )
505
//If there is a following logical partition that starts a mebibyte or less
506
// from the end of this partition, then reserve a mebibyte for the EBR.
507
if ( index_extended != -1 )
509
for ( unsigned int t = 0; t < device .partitions[ index_extended ] .logicals .size(); t++ )
511
if ( ( device .partitions[ index_extended ] .logicals[ t ] .type == TYPE_LOGICAL )
512
&& ( device .partitions[ index_extended ] .logicals[ t ] .sector_start > partition .sector_end )
513
&& ( ( device .partitions[ index_extended ] .logicals[ t ] .sector_start - partition .sector_end )
514
< ( MEBIBYTE / device .sector_size )
517
partition .sector_end -= 1 ;
522
//If this is a GPT partition table then reserve a mebibyte at the end of the device
523
// for the backup partition table
524
if ( device .disktype == "gpt"
525
&& ( ( device .length - partition .sector_end ) <= ( MEBIBYTE / device .sector_size ) )
528
partition .sector_end -= 1 ;
532
diff = (partition .sector_end + 1) % ( MEBIBYTE / partition .sector_size);
534
partition .sector_end -= diff ;
539
bool GParted_Core::snap_to_alignment( const Device & device, Partition & partition, Glib::ustring & error )
543
if ( partition .alignment == ALIGN_CYLINDER )
544
rc = snap_to_cylinder( device, partition, error ) ;
545
else if ( partition .alignment == ALIGN_MEBIBYTE )
546
rc = snap_to_mebibyte( device, partition, error ) ;
548
//Ensure that partition start and end are not beyond the ends of the disk device
549
if ( partition .sector_start < 0 )
550
partition .sector_start = 0 ;
551
if ( partition .sector_end > device .length )
552
partition .sector_end = device .length - 1 ;
554
//do some basic checks on the partition
555
if ( partition .get_sector_length() <= 0 )
557
error = String::ucompose(
558
/* TO TRANSLATORS: looks like A partition cannot have a length of -1 sectors */
559
_("A partition cannot have a length of %1 sectors"),
560
partition .get_sector_length() ) ;
564
if ( partition .get_sector_length() < partition .sectors_used )
566
error = String::ucompose(
567
/* TO TRANSLATORS: looks like A partition with used sectors (2048) greater than its length (1536) is not valid */
568
_("A partition with used sectors (%1) greater than its length (%2) is not valid"),
569
partition .sectors_used,
570
partition .get_sector_length() ) ;
574
//FIXME: it would be perfect if we could check for overlapping with adjacent partitions as well,
575
//however, finding the adjacent partitions is not as easy as it seems and at this moment all the dialogs
576
//already perform these checks. A perfect 'fixme-later' ;)
581
bool GParted_Core::apply_operation_to_disk( Operation * operation )
583
bool succes = false ;
584
libparted_messages .clear() ;
586
if ( calibrate_partition( operation ->partition_original, operation ->operation_detail ) )
587
switch ( operation ->type )
589
case OPERATION_DELETE:
590
succes = Delete( operation ->partition_original, operation ->operation_detail ) ;
592
case OPERATION_CHECK:
593
succes = check_repair_filesystem( operation ->partition_original, operation ->operation_detail ) &&
594
maximize_filesystem( operation ->partition_original, operation ->operation_detail ) ;
596
case OPERATION_CREATE:
597
succes = create( operation ->device,
598
operation ->partition_new,
599
operation ->operation_detail ) ;
601
case OPERATION_RESIZE_MOVE:
602
//in case the to be resized/moved partition was a 'copy of..', we need a real path...
603
operation ->partition_new .add_path( operation ->partition_original .get_path(), true ) ;
604
succes = resize_move( operation ->device,
605
operation ->partition_original,
606
operation ->partition_new,
607
operation ->operation_detail ) ;
609
case OPERATION_FORMAT:
610
succes = format( operation ->partition_new, operation ->operation_detail ) ;
613
//FIXME: in case of a new partition we should make sure the new partition is >= the source partition...
614
//i think it's best to do this in the dialog_paste
615
succes = ( operation ->partition_original .type == TYPE_UNALLOCATED ||
616
calibrate_partition( operation ->partition_new, operation ->operation_detail ) ) &&
618
calibrate_partition( static_cast<OperationCopy*>( operation ) ->partition_copied,
619
operation ->operation_detail ) &&
621
copy( static_cast<OperationCopy*>( operation ) ->partition_copied,
622
operation ->partition_new,
623
static_cast<OperationCopy*>( operation ) ->partition_copied .get_byte_length(),
624
operation ->operation_detail ) ;
626
case OPERATION_LABEL_PARTITION:
627
succes = label_partition( operation ->partition_new, operation ->operation_detail ) ;
631
if ( libparted_messages .size() > 0 )
633
operation ->operation_detail .add_child( OperationDetail( _("libparted messages"), STATUS_INFO ) ) ;
635
for ( unsigned int t = 0 ; t < libparted_messages .size() ; t++ )
636
operation ->operation_detail .get_last_child() .add_child(
637
OperationDetail( libparted_messages[ t ], STATUS_NONE, FONT_ITALIC ) ) ;
643
bool GParted_Core::set_disklabel( const Glib::ustring & device_path, const Glib::ustring & disklabel )
645
bool return_value = false ;
647
if ( open_device_and_disk( device_path, false ) )
649
PedDiskType *type = NULL ;
650
type = ped_disk_type_get( disklabel .c_str() ) ;
654
lp_disk = ped_disk_new_fresh( lp_device, type );
656
return_value = commit() ;
659
close_device_and_disk() ;
662
#ifndef USE_LIBPARTED_DMRAID
663
//delete and recreate disk entries if dmraid
665
if ( return_value && dmraid .is_dmraid_device( device_path ) )
667
dmraid .purge_dev_map_entries( device_path ) ;
668
dmraid .create_dev_map_entries( device_path ) ;
672
return return_value ;
675
bool GParted_Core::toggle_flag( const Partition & partition, const Glib::ustring & flag, bool state )
677
bool succes = false ;
679
if ( open_device_and_disk( partition .device_path ) )
681
lp_partition = NULL ;
682
if ( partition .type == GParted::TYPE_EXTENDED )
683
lp_partition = ped_disk_extended_partition( lp_disk ) ;
685
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
689
PedPartitionFlag lp_flag = ped_partition_flag_get_by_name( flag .c_str() ) ;
691
if ( lp_flag > 0 && ped_partition_set_flag( lp_partition, lp_flag, state ) )
695
close_device_and_disk() ;
701
const std::vector<FS> & GParted_Core::get_filesystems() const
706
const FS & GParted_Core::get_fs( GParted::FILESYSTEM filesystem ) const
708
for ( unsigned int t = 0 ; t < FILESYSTEMS .size() ; t++ )
709
if ( FILESYSTEMS[ t ] .filesystem == filesystem )
710
return FILESYSTEMS[ t ] ;
712
return FILESYSTEMS .back() ;
715
std::vector<Glib::ustring> GParted_Core::get_disklabeltypes()
717
std::vector<Glib::ustring> disklabeltypes ;
719
//msdos should be first in the list
720
disklabeltypes .push_back( "msdos" ) ;
722
PedDiskType *disk_type ;
723
for ( disk_type = ped_disk_type_get_next( NULL ) ; disk_type ; disk_type = ped_disk_type_get_next( disk_type ) )
724
if ( Glib::ustring( disk_type->name ) != "msdos" )
725
disklabeltypes .push_back( disk_type->name ) ;
727
return disklabeltypes ;
730
std::vector<Glib::ustring> GParted_Core::get_all_mountpoints()
732
std::vector<Glib::ustring> mountpoints ;
734
for ( iter_mp = mount_info .begin() ; iter_mp != mount_info .end() ; ++iter_mp )
735
mountpoints .insert( mountpoints .end(), iter_mp ->second .begin(), iter_mp ->second .end() ) ;
740
std::map<Glib::ustring, bool> GParted_Core::get_available_flags( const Partition & partition )
742
std::map<Glib::ustring, bool> flag_info ;
744
if ( open_device_and_disk( partition .device_path ) )
746
lp_partition = NULL ;
747
if ( partition .type == GParted::TYPE_EXTENDED )
748
lp_partition = ped_disk_extended_partition( lp_disk ) ;
750
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
754
for ( unsigned int t = 0 ; t < flags .size() ; t++ )
755
if ( ped_partition_is_flag_available( lp_partition, flags[ t ] ) )
756
flag_info[ ped_partition_flag_get_name( flags[ t ] ) ] =
757
ped_partition_get_flag( lp_partition, flags[ t ] ) ;
760
close_device_and_disk() ;
766
Glib::ustring GParted_Core::get_libparted_version()
768
return ped_get_version() ;
771
//private functions...
773
void GParted_Core::init_maps()
775
mount_info .clear() ;
776
fstab_info .clear() ;
778
read_mountpoints_from_file( "/proc/mounts", mount_info ) ;
779
read_mountpoints_from_file_swaps( "/proc/swaps", mount_info ) ;
780
read_mountpoints_from_file( "/etc/mtab", mount_info ) ;
781
read_mountpoints_from_file( "/etc/fstab", fstab_info ) ;
783
//sort the mount points and remove duplicates.. (no need to do this for fstab_info)
784
for ( iter_mp = mount_info .begin() ; iter_mp != mount_info .end() ; ++iter_mp )
786
std::sort( iter_mp ->second .begin(), iter_mp ->second .end() ) ;
788
iter_mp ->second .erase(
789
std::unique( iter_mp ->second .begin(), iter_mp ->second .end() ),
790
iter_mp ->second .end() ) ;
794
void GParted_Core::read_mountpoints_from_file(
795
const Glib::ustring & filename,
796
std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
798
FS_Info fs_info ; //Use cache of file system information
800
FILE* fp = setmntent( filename .c_str(), "r" ) ;
805
struct mntent* p = NULL ;
807
while ( (p = getmntent(fp)) != NULL )
809
Glib::ustring node = p->mnt_fsname ;
811
Glib::ustring uuid = Utils::regexp_label( node, "^UUID=(.*)" ) ;
812
if ( ! uuid .empty() )
813
node = fs_info .get_path_by_uuid( uuid ) ;
815
Glib::ustring label = Utils::regexp_label( node, "^LABEL=(.*)" ) ;
816
if ( ! label .empty() )
817
node = fs_info .get_path_by_label( label ) ;
819
if ( ! node .empty() )
821
Glib::ustring mountpoint = p->mnt_dir ;
823
//Only add node path(s) if mount point exists
824
if ( file_test( mountpoint, Glib::FILE_TEST_EXISTS ) )
826
map[ node ] .push_back( mountpoint ) ;
828
//If node is a symbolic link (e.g., /dev/root)
829
// then find real path and add entry
830
if ( file_test( node, Glib::FILE_TEST_IS_SYMLINK ) )
833
//FIXME: it seems realpath is very unsafe to use (manpage)...
834
if ( realpath( node .c_str(), c_str ) != NULL )
835
map[ c_str ] .push_back( mountpoint ) ;
844
void GParted_Core::read_mountpoints_from_file_swaps(
845
const Glib::ustring & filename,
846
std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
851
std::ifstream file( filename .c_str() ) ;
854
while ( getline( file, line ) )
856
node = Utils::regexp_label( line, "^(/[^ ]+)" ) ;
857
if ( node .size() > 0 )
858
map[ node ] .push_back( "" /* no mountpoint for swap */ ) ;
864
Glib::ustring GParted_Core::get_partition_path( PedPartition * lp_partition )
866
char * lp_path; //we have to free the result of ped_partition_get_path()
867
Glib::ustring partition_path = "Partition path not found";
869
lp_path = ped_partition_get_path(lp_partition);
870
if ( lp_path != NULL )
872
partition_path = lp_path;
876
#ifndef USE_LIBPARTED_DMRAID
877
//Ensure partition path name is compatible with dmraid
878
DMRaid dmraid; //Use cache of dmraid device information
879
if ( dmraid .is_dmraid_supported()
880
&& dmraid .is_dmraid_device( partition_path )
883
partition_path = dmraid .make_path_dmraid_compatible(partition_path);
887
return partition_path ;
890
void GParted_Core::set_device_partitions( Device & device )
893
Proc_Partitions_Info pp_info ; //Use cache of proc partitions information
894
FS_Info fs_info ; //Use cache of file system information
895
#ifndef USE_LIBPARTED_DMRAID
896
DMRaid dmraid ; //Use cache of dmraid device information
900
device .partitions .clear() ;
902
lp_partition = ped_disk_next_partition( lp_disk, NULL ) ;
903
while ( lp_partition )
905
libparted_messages .clear() ;
906
partition_temp .Reset() ;
907
bool partition_is_busy = false ;
909
//Retrieve partition path
910
Glib::ustring partition_path = get_partition_path( lp_partition );
912
switch ( lp_partition ->type )
914
case PED_PARTITION_NORMAL:
915
case PED_PARTITION_LOGICAL:
916
#ifndef USE_LIBPARTED_DMRAID
917
//Handle dmraid devices differently because the minor number might not
918
// match the last number of the partition filename as shown by "ls -l /dev/mapper"
919
// This mismatch causes incorrect identification of busy partitions in ped_partition_is_busy().
920
if ( dmraid .is_dmraid_device( device .get_path() ) )
922
//Try device_name + partition_number
923
iter_mp = mount_info .find( device .get_path() + Utils::num_to_str( lp_partition ->num ) ) ;
924
if ( iter_mp != mount_info .end() )
925
partition_is_busy = true ;
926
//Try device_name + p + partition_number
927
iter_mp = mount_info .find( device .get_path() + "p" + Utils::num_to_str( lp_partition ->num ) ) ;
928
if ( iter_mp != mount_info .end() )
929
partition_is_busy = true ;
933
partition_is_busy = ped_partition_is_busy( lp_partition ) ;
935
partition_temp .Set( device .get_path(),
938
lp_partition ->type == 0 ? GParted::TYPE_PRIMARY : GParted::TYPE_LOGICAL,
940
lp_partition ->geom .start,
941
lp_partition ->geom .end,
944
partition_is_busy ) ;
946
partition_temp .add_paths( pp_info .get_alternate_paths( partition_temp .get_path() ) ) ;
947
set_flags( partition_temp ) ;
949
if ( partition_temp .busy && partition_temp .partition_number > device .highest_busy )
950
device .highest_busy = partition_temp .partition_number ;
954
case PED_PARTITION_EXTENDED:
955
#ifndef USE_LIBPARTED_DMRAID
956
//Handle dmraid devices differently because the minor number might not
957
// match the last number of the partition filename as shown by "ls -l /dev/mapper"
958
// This mismatch causes incorrect identification of busy partitions in ped_partition_is_busy().
959
if ( dmraid .is_dmraid_device( device .get_path() ) )
961
for ( unsigned int k = 5; k < 255; k++ )
963
//Try device_name + [5 to 255]
964
iter_mp = mount_info .find( device .get_path() + Utils::num_to_str( k ) ) ;
965
if ( iter_mp != mount_info .end() )
966
partition_is_busy = true ;
967
//Try device_name + p + [5 to 255]
968
iter_mp = mount_info .find( device .get_path() + "p" + Utils::num_to_str( k ) ) ;
969
if ( iter_mp != mount_info .end() )
970
partition_is_busy = true ;
975
partition_is_busy = ped_partition_is_busy( lp_partition ) ;
977
partition_temp .Set( device .get_path(),
980
GParted::TYPE_EXTENDED,
981
GParted::FS_EXTENDED,
982
lp_partition ->geom .start,
983
lp_partition ->geom .end,
986
partition_is_busy ) ;
988
partition_temp .add_paths( pp_info .get_alternate_paths( partition_temp .get_path() ) ) ;
989
set_flags( partition_temp ) ;
991
EXT_INDEX = device .partitions .size() ;
998
//Avoid reading additional file system information if there is no path
999
if ( partition_temp .get_path() != "" )
1001
//Retrieve file system label
1002
read_label( partition_temp ) ;
1003
if ( partition_temp .label .empty() )
1005
bool label_found = false ;
1006
partition_temp .label = fs_info .get_label( partition_temp .get_path(), label_found ) ;
1008
partition_temp .uuid = fs_info .get_uuid( partition_temp .get_path() ) ;
1011
partition_temp .messages .insert( partition_temp .messages .end(),
1012
libparted_messages. begin(),
1013
libparted_messages .end() ) ;
1015
//if there's an end, there's a partition ;)
1016
if ( partition_temp .sector_end > -1 )
1018
if ( ! partition_temp .inside_extended )
1019
device .partitions .push_back( partition_temp );
1021
device .partitions[ EXT_INDEX ] .logicals .push_back( partition_temp ) ;
1024
//next partition (if any)
1025
lp_partition = ped_disk_next_partition( lp_disk, lp_partition ) ;
1028
if ( EXT_INDEX > -1 )
1029
insert_unallocated( device .get_path(),
1030
device .partitions[ EXT_INDEX ] .logicals,
1031
device .partitions[ EXT_INDEX ] .sector_start,
1032
device .partitions[ EXT_INDEX ] .sector_end,
1033
device .sector_size,
1036
insert_unallocated( device .get_path(), device .partitions, 0, device .length -1, device .sector_size, false ) ;
1039
GParted::FILESYSTEM GParted_Core::get_filesystem()
1041
char magic1[16] = "";
1042
char magic2[16] = "";
1044
//Check for LUKS encryption prior to libparted file system detection.
1045
// Otherwise encrypted file systems such as ext3 will be detected by
1046
// libparted as 'ext3'.
1049
char * buf = static_cast<char *>( malloc( lp_device ->sector_size ) ) ;
1052
ped_device_open( lp_device );
1053
ped_geometry_read( & lp_partition ->geom, buf, 0, 1 ) ;
1054
memcpy(magic1, buf+0, 6) ; //set binary magic data
1055
ped_device_close( lp_device );
1058
if ( 0 == memcmp( magic1 , "LUKS\xBA\xBE", 6 ) )
1060
temp = _( "Linux Unified Key Setup encryption is not yet supported." ) ;
1062
partition_temp .messages .push_back( temp ) ;
1063
return GParted::FS_LUKS ;
1068
Glib::ustring fs_type = "" ;
1070
//Standard libparted file system detection
1071
if ( lp_partition && lp_partition ->fs_type )
1073
fs_type = lp_partition ->fs_type ->name ;
1075
//TODO: Temporary code to detect ext4.
1076
// Replace when libparted >= 1.9.0 is chosen as minimum required version.
1077
temp = fs_info .get_fs_type( get_partition_path( lp_partition ) ) ;
1078
if ( temp == "ext4" || temp == "ext4dev" )
1082
//FS_Info (blkid) file system detection because current libparted (v2.2) does not
1083
// appear to detect file systems for sector sizes other than 512 bytes.
1084
if ( fs_type .empty() )
1086
//TODO: blkid does not return anything for an "extended" partition. Need to handle this somehow
1087
fs_type = fs_info.get_fs_type( get_partition_path( lp_partition ) ) ;
1090
if ( ! fs_type .empty() )
1092
if ( fs_type == "extended" )
1093
return GParted::FS_EXTENDED ;
1094
else if ( fs_type == "btrfs" )
1095
return GParted::FS_BTRFS ;
1096
else if ( fs_type == "exfat" )
1097
return GParted::FS_EXFAT ;
1098
else if ( fs_type == "ext2" )
1099
return GParted::FS_EXT2 ;
1100
else if ( fs_type == "ext3" )
1101
return GParted::FS_EXT3 ;
1102
else if ( fs_type == "ext4" ||
1103
fs_type == "ext4dev" )
1104
return GParted::FS_EXT4 ;
1105
else if ( fs_type == "linux-swap" ||
1106
fs_type == "linux-swap(v1)" ||
1107
fs_type == "linux-swap(new)" ||
1108
fs_type == "linux-swap(v0)" ||
1109
fs_type == "linux-swap(old)" ||
1111
return GParted::FS_LINUX_SWAP ;
1112
else if ( fs_type == "fat16" )
1113
return GParted::FS_FAT16 ;
1114
else if ( fs_type == "fat32" )
1115
return GParted::FS_FAT32 ;
1116
else if ( fs_type == "ntfs" )
1117
return GParted::FS_NTFS ;
1118
else if ( fs_type == "reiserfs" )
1119
return GParted::FS_REISERFS ;
1120
else if ( fs_type == "xfs" )
1121
return GParted::FS_XFS ;
1122
else if ( fs_type == "jfs" )
1123
return GParted::FS_JFS ;
1124
else if ( fs_type == "hfs" )
1125
return GParted::FS_HFS ;
1126
else if ( fs_type == "hfs+" ||
1127
fs_type == "hfsplus" )
1128
return GParted::FS_HFSPLUS ;
1129
else if ( fs_type == "ufs" )
1130
return GParted::FS_UFS ;
1135
//other file systems libparted couldn't detect (i've send patches for these file systems to the parted guys)
1136
// - no patches sent to parted for lvm2, or luks
1139
buf = static_cast<char *>( malloc( lp_device ->sector_size ) ) ;
1142
ped_device_open( lp_device );
1143
ped_geometry_read( & lp_partition ->geom
1145
, (65536 / lp_device ->sector_size)
1148
memcpy(magic1, buf+0, 7) ; //set binary magic data
1149
ped_device_close( lp_device );
1152
if ( 0 == memcmp( magic1, "ReIsEr4", 7 ) )
1153
return GParted::FS_REISER4 ;
1157
//NOTE: lvm2 is not a file system but we do wish to recognize the Physical Volume
1158
buf = static_cast<char *>( malloc( lp_device ->sector_size ) ) ;
1161
ped_device_open( lp_device );
1162
if ( lp_device ->sector_size == 512 )
1164
ped_geometry_read( & lp_partition ->geom, buf, 1, 1 ) ;
1165
memcpy(magic1, buf+ 0, 8) ; // set binary magic data
1166
memcpy(magic2, buf+24, 4) ; // set binary magic data
1170
ped_geometry_read( & lp_partition ->geom, buf, 0, 1 ) ;
1171
memcpy(magic1, buf+ 0+512, 8) ; // set binary magic data
1172
memcpy(magic2, buf+24+512, 4) ; // set binary magic data
1174
ped_device_close( lp_device );
1177
if ( 0 == memcmp( magic1, "LABELONE", 8 )
1178
&& 0 == memcmp( magic2, "LVM2", 4 ) )
1180
temp = _( "Logical Volume Management is not yet supported." ) ;
1182
partition_temp .messages .push_back( temp ) ;
1183
return GParted::FS_LVM2 ;
1188
const Sector BTRFS_SUPER_INFO_SIZE = 4096 ;
1189
const Sector BTRFS_SUPER_INFO_OFFSET = (64 * 1024) ;
1190
const char* const BTRFS_SIGNATURE = "_BHRfS_M" ;
1192
char buf_btrfs[BTRFS_SUPER_INFO_SIZE] ;
1194
ped_device_open( lp_device ) ;
1195
ped_geometry_read( & lp_partition ->geom
1197
, (BTRFS_SUPER_INFO_OFFSET / lp_device ->sector_size)
1198
, (BTRFS_SUPER_INFO_SIZE / lp_device ->sector_size)
1200
memcpy(magic1, buf_btrfs+64, strlen(BTRFS_SIGNATURE) ) ; //set binary magic data
1201
ped_device_close( lp_device ) ;
1203
if ( 0 == memcmp( magic1, BTRFS_SIGNATURE, strlen(BTRFS_SIGNATURE) ) )
1205
return GParted::FS_BTRFS ;
1208
//no file system found....
1209
temp = _( "Unable to detect file system! Possible reasons are:" ) ;
1211
temp += _( "The file system is damaged" ) ;
1213
temp += _( "The file system is unknown to GParted" ) ;
1215
temp += _( "There is no file system available (unformatted)" ) ;
1217
/* TO TRANSLATORS: looks like The device entry /dev/sda5 is missing */
1218
temp += String::ucompose( _( "The device entry %1 is missing" ), get_partition_path( lp_partition ) ) ;
1220
partition_temp .messages .push_back( temp ) ;
1222
return GParted::FS_UNKNOWN ;
1225
void GParted_Core::read_label( Partition & partition )
1227
if ( partition .type != TYPE_EXTENDED )
1229
switch( get_fs( partition .filesystem ) .read_label )
1232
if ( set_proper_filesystem( partition .filesystem ) )
1233
p_filesystem ->read_label( partition ) ;
1235
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
1246
void GParted_Core::insert_unallocated( const Glib::ustring & device_path,
1247
std::vector<Partition> & partitions,
1250
Byte_Value sector_size,
1251
bool inside_extended )
1253
partition_temp .Reset() ;
1254
partition_temp .Set_Unallocated( device_path, 0, 0, sector_size, inside_extended ) ;
1256
//if there are no partitions at all..
1257
if ( partitions .empty() )
1259
partition_temp .sector_start = start ;
1260
partition_temp .sector_end = end ;
1262
partitions .push_back( partition_temp );
1267
//start <---> first partition start
1268
if ( (partitions .front() .sector_start - start) > (MEBIBYTE / sector_size) )
1270
partition_temp .sector_start = start ;
1271
partition_temp .sector_end = partitions .front() .sector_start -1 ;
1273
partitions .insert( partitions .begin(), partition_temp );
1276
//look for gaps in between
1277
for ( unsigned int t =0 ; t < partitions .size() -1 ; t++ )
1279
if ( ( ( partitions[ t + 1 ] .sector_start - partitions[ t ] .sector_end - 1 ) > (MEBIBYTE / sector_size) )
1280
|| ( ( partitions[ t + 1 ] .type != TYPE_LOGICAL ) // Only show exactly 1 MiB if following partition is not logical.
1281
&& ( ( partitions[ t + 1 ] .sector_start - partitions[ t ] .sector_end - 1 ) == (MEBIBYTE / sector_size) )
1285
partition_temp .sector_start = partitions[ t ] .sector_end +1 ;
1286
partition_temp .sector_end = partitions[ t +1 ] .sector_start -1 ;
1288
partitions .insert( partitions .begin() + ++t, partition_temp );
1292
//last partition end <---> end
1293
if ( (end - partitions .back() .sector_end) >= (MEBIBYTE / sector_size) )
1295
partition_temp .sector_start = partitions .back() .sector_end +1 ;
1296
partition_temp .sector_end = end ;
1298
partitions .push_back( partition_temp );
1302
void GParted_Core::set_mountpoints( std::vector<Partition> & partitions )
1304
#ifndef USE_LIBPARTED_DMRAID
1305
DMRaid dmraid ; //Use cache of dmraid device information
1307
for ( unsigned int t = 0 ; t < partitions .size() ; t++ )
1309
if ( ( partitions[ t ] .type == GParted::TYPE_PRIMARY ||
1310
partitions[ t ] .type == GParted::TYPE_LOGICAL
1312
partitions[ t ] .filesystem != GParted::FS_LINUX_SWAP &&
1313
partitions[ t ] .filesystem != GParted::FS_LVM2 &&
1314
partitions[ t ] .filesystem != GParted::FS_LUKS
1317
if ( partitions[ t ] .busy )
1319
#ifndef USE_LIBPARTED_DMRAID
1320
//Handle dmraid devices differently because there may be more
1321
// than one partition name.
1322
// E.g., there might be names with and/or without a 'p' between
1323
// the device name and partition number.
1324
if ( dmraid .is_dmraid_device( partitions[ t ] .device_path ) )
1326
//Try device_name + partition_number
1327
iter_mp = mount_info .find( partitions[ t ] .device_path + Utils::num_to_str( partitions[ t ] .partition_number ) ) ;
1328
if ( iter_mp != mount_info .end() )
1330
partitions[ t ] .add_mountpoints( iter_mp ->second ) ;
1333
//Try device_name + p + partition_number
1334
iter_mp = mount_info .find( partitions[ t ] .device_path + "p" + Utils::num_to_str( partitions[ t ] .partition_number ) ) ;
1335
if ( iter_mp != mount_info .end() )
1337
partitions[ t ] .add_mountpoints( iter_mp ->second ) ;
1344
//Normal device, not DMRaid device
1345
for ( unsigned int i = 0 ; i < partitions[ t ] .get_paths() .size() ; i++ )
1347
iter_mp = mount_info .find( partitions[ t ] .get_paths()[ i ] ) ;
1348
if ( iter_mp != mount_info .end() )
1350
partitions[ t ] .add_mountpoints( iter_mp ->second ) ;
1354
#ifndef USE_LIBPARTED_DMRAID
1358
if ( partitions[ t ] .get_mountpoints() .empty() )
1359
partitions[ t ] .messages .push_back( _("Unable to find mount point") ) ;
1363
iter_mp = fstab_info .find( partitions[ t ] .get_path() );
1364
if ( iter_mp != fstab_info .end() )
1365
partitions[ t ] .add_mountpoints( iter_mp ->second ) ;
1368
else if ( partitions[ t ] .type == GParted::TYPE_EXTENDED )
1369
set_mountpoints( partitions[ t ] .logicals ) ;
1373
void GParted_Core::set_used_sectors( std::vector<Partition> & partitions )
1375
struct statvfs sfs ;
1377
for ( unsigned int t = 0 ; t < partitions .size() ; t++ )
1379
if ( partitions[ t ] .filesystem != GParted::FS_LINUX_SWAP &&
1380
partitions[ t ] .filesystem != GParted::FS_LUKS &&
1381
partitions[ t ] .filesystem != GParted::FS_LVM2 &&
1382
partitions[ t ] .filesystem != GParted::FS_UNKNOWN
1385
if ( partitions[ t ] .type == GParted::TYPE_PRIMARY ||
1386
partitions[ t ] .type == GParted::TYPE_LOGICAL )
1388
if ( partitions[ t ] .busy )
1390
if ( partitions[ t ] .get_mountpoints() .size() > 0 )
1392
if ( statvfs( partitions[ t ] .get_mountpoint() .c_str(), &sfs ) == 0 )
1393
partitions[ t ] .Set_Unused( sfs .f_bfree * (sfs .f_bsize / partitions[ t ] .sector_size) ) ;
1395
partitions[ t ] .messages .push_back(
1397
partitions[ t ] .get_mountpoint() +
1399
Glib::strerror( errno ) ) ;
1404
switch( get_fs( partitions[ t ] .filesystem ) .read )
1406
case GParted::FS::EXTERNAL :
1407
if ( set_proper_filesystem( partitions[ t ] .filesystem ) )
1408
p_filesystem ->set_used_sectors( partitions[ t ] ) ;
1410
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
1411
case GParted::FS::LIBPARTED :
1412
LP_set_used_sectors( partitions[ t ] ) ;
1421
if ( partitions[ t ] .sectors_used == -1 )
1423
temp = _("Unable to read the contents of this file system!") ;
1425
temp += _("Because of this some operations may be unavailable.") ;
1426
if ( ! Utils::get_filesystem_software( partitions[ t ] .filesystem ) .empty() )
1429
temp += _( "The cause might be a missing software package.") ;
1431
/*TO TRANSLATORS: looks like The following list of software packages is required for NTFS file system support: ntfsprogs. */
1432
temp += String::ucompose( _("The following list of software packages is required for %1 file system support: %2."),
1433
Utils::get_filesystem_string( partitions[ t ] .filesystem ),
1434
Utils::get_filesystem_software( partitions[ t ] .filesystem )
1437
partitions[ t ] .messages .push_back( temp ) ;
1440
else if ( partitions[ t ] .type == GParted::TYPE_EXTENDED )
1441
set_used_sectors( partitions[ t ] .logicals ) ;
1446
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
1447
void GParted_Core::LP_set_used_sectors( Partition & partition )
1449
PedFileSystem *fs = NULL;
1450
PedConstraint *constraint = NULL;
1454
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
1458
fs = ped_file_system_open( & lp_partition ->geom );
1462
constraint = ped_file_system_get_resize_constraint( fs ) ;
1465
partition .Set_Unused( partition .get_sector_length() - constraint ->min_size ) ;
1467
ped_constraint_destroy( constraint );
1470
ped_file_system_close( fs ) ;
1477
void GParted_Core::set_flags( Partition & partition )
1479
for ( unsigned int t = 0 ; t < flags .size() ; t++ )
1480
if ( ped_partition_is_flag_available( lp_partition, flags[ t ] ) &&
1481
ped_partition_get_flag( lp_partition, flags[ t ] ) )
1482
partition .flags .push_back( ped_partition_flag_get_name( flags[ t ] ) ) ;
1485
bool GParted_Core::create( const Device & device, Partition & new_partition, OperationDetail & operationdetail )
1487
if ( new_partition .type == GParted::TYPE_EXTENDED )
1489
return create_partition( new_partition, operationdetail ) ;
1491
else if ( create_partition( new_partition, operationdetail, (get_fs( new_partition .filesystem ) .MIN / new_partition .sector_size) ) )
1493
if ( new_partition .filesystem == GParted::FS_UNFORMATTED )
1496
return set_partition_type( new_partition, operationdetail ) &&
1497
create_filesystem( new_partition, operationdetail ) ;
1503
bool GParted_Core::create_partition( Partition & new_partition, OperationDetail & operationdetail, Sector min_size )
1505
operationdetail .add_child( OperationDetail( _("create empty partition") ) ) ;
1507
new_partition .partition_number = 0 ;
1509
if ( open_device_and_disk( new_partition .device_path ) )
1511
PedPartitionType type;
1512
lp_partition = NULL ;
1513
PedConstraint *constraint = NULL ;
1514
PedFileSystemType* fs_type = NULL ;
1516
//create new partition
1517
switch ( new_partition .type )
1519
case GParted::TYPE_PRIMARY:
1520
type = PED_PARTITION_NORMAL ;
1522
case GParted::TYPE_LOGICAL:
1523
type = PED_PARTITION_LOGICAL ;
1525
case GParted::TYPE_EXTENDED:
1526
type = PED_PARTITION_EXTENDED ;
1530
type = PED_PARTITION_FREESPACE;
1533
if ( new_partition .type != GParted::TYPE_EXTENDED )
1534
fs_type = ped_file_system_type_get( "ext2" ) ;
1536
lp_partition = ped_partition_new( lp_disk,
1539
new_partition .sector_start,
1540
new_partition .sector_end ) ;
1544
if ( new_partition .alignment == ALIGN_STRICT
1545
|| new_partition .alignment == ALIGN_MEBIBYTE
1548
PedGeometry *geom = ped_geometry_new( lp_device,
1549
new_partition .sector_start,
1550
new_partition .get_sector_length() ) ;
1553
constraint = ped_constraint_exact( geom ) ;
1556
constraint = ped_constraint_any( lp_device );
1561
&& new_partition .filesystem != FS_XFS // Permit copying to smaller xfs partition
1563
constraint ->min_size = min_size ;
1565
if ( ped_disk_add_partition( lp_disk, lp_partition, constraint ) && commit() )
1567
Glib::ustring partition_path = get_partition_path( lp_partition ) ;
1568
new_partition .add_path( partition_path, true ) ;
1570
new_partition .partition_number = lp_partition ->num ;
1571
new_partition .sector_start = lp_partition ->geom .start ;
1572
new_partition .sector_end = lp_partition ->geom .end ;
1574
operationdetail .get_last_child() .add_child( OperationDetail(
1575
String::ucompose( _("path: %1"), new_partition .get_path() ) + "\n" +
1576
String::ucompose( _("start: %1"), new_partition .sector_start ) + "\n" +
1577
String::ucompose( _("end: %1"), new_partition .sector_end ) + "\n" +
1578
String::ucompose( _("size: %1 (%2)"),
1579
new_partition .get_sector_length(),
1580
Utils::format_size( new_partition .get_sector_length(), new_partition .sector_size ) ),
1585
ped_constraint_destroy( constraint );
1589
close_device_and_disk() ;
1592
bool succes = new_partition .partition_number > 0
1593
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
1594
&& erase_filesystem_signatures( new_partition )
1598
#ifndef USE_LIBPARTED_DMRAID
1599
//create dev map entries if dmraid
1601
if ( succes && dmraid .is_dmraid_device( new_partition .device_path ) )
1602
succes = dmraid .create_dev_map_entries( new_partition, operationdetail .get_last_child() ) ;
1605
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
1610
bool GParted_Core::create_filesystem( const Partition & partition, OperationDetail & operationdetail )
1612
/*TO TRANSLATORS: looks like create new ext3 file system */
1613
operationdetail .add_child( OperationDetail( String::ucompose(
1614
_("create new %1 file system"),
1615
Utils::get_filesystem_string( partition .filesystem ) ) ) ) ;
1617
bool succes = false ;
1618
switch ( get_fs( partition .filesystem ) .create )
1620
case GParted::FS::NONE:
1622
case GParted::FS::GPARTED:
1624
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
1625
case GParted::FS::LIBPARTED:
1628
case GParted::FS::EXTERNAL:
1629
succes = set_proper_filesystem( partition .filesystem ) &&
1630
p_filesystem ->create( partition, operationdetail .get_last_child() ) ;
1635
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
1639
bool GParted_Core::format( const Partition & partition, OperationDetail & operationdetail )
1641
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
1642
//remove all file system signatures...
1643
erase_filesystem_signatures( partition ) ;
1646
return set_partition_type( partition, operationdetail ) && create_filesystem( partition, operationdetail ) ;
1649
bool GParted_Core::Delete( const Partition & partition, OperationDetail & operationdetail )
1651
operationdetail .add_child( OperationDetail( _("delete partition") ) ) ;
1653
bool succes = false ;
1654
if ( open_device_and_disk( partition .device_path ) )
1656
if ( partition .type == TYPE_EXTENDED )
1657
lp_partition = ped_disk_extended_partition( lp_disk ) ;
1659
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
1661
succes = ped_disk_delete_partition( lp_disk, lp_partition ) && commit() ;
1663
close_device_and_disk() ;
1666
#ifndef USE_LIBPARTED_DMRAID
1667
//delete partition dev mapper entry, and delete and recreate all other affected dev mapper entries if dmraid
1669
if ( succes && dmraid .is_dmraid_device( partition .device_path ) )
1671
//Open disk handle before and close after to prevent application crash.
1672
if ( open_device_and_disk( partition .device_path ) )
1674
if ( ! dmraid .delete_affected_dev_map_entries( partition, operationdetail .get_last_child() ) )
1675
succes = false ; //comand failed
1677
if ( ! dmraid .create_dev_map_entries( partition, operationdetail .get_last_child() ) )
1678
succes = false ; //command failed
1680
close_device_and_disk() ;
1685
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
1689
bool GParted_Core::label_partition( const Partition & partition, OperationDetail & operationdetail )
1691
if( partition .label .empty() ) {
1692
operationdetail .add_child( OperationDetail( String::ucompose(
1693
_("Clear partition label on %1"),
1694
partition .get_path()
1697
operationdetail .add_child( OperationDetail( String::ucompose(
1698
_("Set partition label to \"%1\" on %2"),
1699
partition .label, partition .get_path()
1703
bool succes = false ;
1704
if ( partition .type != TYPE_EXTENDED )
1706
switch( get_fs( partition .filesystem ) .write_label )
1709
succes = set_proper_filesystem( partition .filesystem ) &&
1710
p_filesystem ->write_label( partition, operationdetail .get_last_child() ) ;
1712
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
1722
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
1727
bool GParted_Core::resize_move( const Device & device,
1728
const Partition & partition_old,
1729
Partition & partition_new,
1730
OperationDetail & operationdetail )
1732
if ( (partition_new .alignment == ALIGN_STRICT)
1733
|| (partition_new .alignment == ALIGN_MEBIBYTE)
1734
|| partition_new .strict_start
1735
|| calculate_exact_geom( partition_old, partition_new, operationdetail )
1738
if ( partition_old .type == TYPE_EXTENDED )
1739
return resize_move_partition( partition_old, partition_new, operationdetail ) ;
1741
if ( partition_new .sector_start == partition_old .sector_start )
1742
return resize( partition_old, partition_new, operationdetail ) ;
1744
if ( partition_new .get_sector_length() == partition_old .get_sector_length() )
1745
return move( device, partition_old, partition_new, operationdetail ) ;
1748
if ( partition_new .get_sector_length() > partition_old .get_sector_length() )
1750
//first move, then grow. Since old.length < new.length and new.start is valid, temp is valid.
1751
temp = partition_new ;
1752
temp .sector_end = temp .sector_start + partition_old .get_sector_length() -1 ;
1755
if ( partition_new .get_sector_length() < partition_old .get_sector_length() )
1757
//first shrink, then move. Since new.length < old.length and old.start is valid, temp is valid.
1758
temp = partition_old ;
1759
temp .sector_end = partition_old .sector_start + partition_new .get_sector_length() -1 ;
1762
PartitionAlignment previous_alignment = temp .alignment ;
1763
temp .alignment = ALIGN_STRICT ;
1764
bool succes = resize_move( device, partition_old, temp, operationdetail ) ;
1765
temp .alignment = previous_alignment ;
1767
return succes && resize_move( device, temp, partition_new, operationdetail ) ;
1773
bool GParted_Core::move( const Device & device,
1774
const Partition & partition_old,
1775
const Partition & partition_new,
1776
OperationDetail & operationdetail )
1778
if ( partition_old .get_sector_length() != partition_new .get_sector_length() )
1780
operationdetail .add_child( OperationDetail(
1781
/* TO TRANSLATORS: moving requires old and new length to be the same
1782
* means that the length in bytes of the old partition and new partition
1783
* must be the same. If the sector sizes of the old partition and the
1784
* new partition are the same, then the length in sectors must be the same.
1786
_("moving requires old and new length to be the same"), STATUS_ERROR, FONT_ITALIC ) ) ;
1791
bool succes = false ;
1792
if ( check_repair_filesystem( partition_old, operationdetail ) )
1794
//NOTE: Logical partitions are preceded by meta data. To prevent this
1795
// meta data from being overwritten we first expand the partition to
1796
// encompass all of the space involved in the move. In this way we
1797
// prevent overwriting the meta data for this partition when we move
1798
// this partition to the left. We also prevent overwriting the meta
1799
// data of a following partition when we move this partition to the
1801
Partition partition_all_space = partition_old ;
1802
partition_all_space .alignment = ALIGN_STRICT ;
1803
if ( partition_new .sector_start < partition_all_space. sector_start )
1804
partition_all_space .sector_start = partition_new. sector_start ;
1805
if ( partition_new .sector_end > partition_all_space.sector_end )
1806
partition_all_space .sector_end = partition_new. sector_end ;
1808
//Make old partition all encompassing and if move file system fails
1809
// then return partition table to original state
1810
if ( resize_move_partition( partition_old, partition_all_space, operationdetail ) )
1812
//Note move of file system is from old values to new values, not from
1813
// the all encompassing values.
1814
if ( ! move_filesystem( partition_old, partition_new, operationdetail ) )
1816
operationdetail .add_child( OperationDetail( _("rollback last change to the partition table") ) ) ;
1818
Partition partition_restore = partition_old ;
1819
partition_restore .alignment = ALIGN_STRICT ; //Ensure that old partition boundaries are not modified
1820
if ( resize_move_partition( partition_all_space, partition_restore, operationdetail .get_last_child() ) )
1821
operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
1823
operationdetail .get_last_child() .set_status( STATUS_ERROR ) ;
1829
//Make new partition from all encompassing partition
1830
succes = succes && resize_move_partition( partition_all_space, partition_new, operationdetail ) ;
1833
&& update_bootsector( partition_new, operationdetail )
1834
&& ( //Do not maximize file system if new size <= old
1835
( partition_new .get_sector_length() <= partition_old .get_sector_length() )
1836
|| ( check_repair_filesystem( partition_new, operationdetail )
1837
&& maximize_filesystem( partition_new, operationdetail )
1847
bool GParted_Core::move_filesystem( const Partition & partition_old,
1848
const Partition & partition_new,
1849
OperationDetail & operationdetail )
1851
if ( partition_new .sector_start < partition_old .sector_start )
1852
operationdetail .add_child( OperationDetail( _("move file system to the left") ) ) ;
1853
else if ( partition_new .sector_start > partition_old .sector_start )
1854
operationdetail .add_child( OperationDetail( _("move file system to the right") ) ) ;
1857
operationdetail .add_child( OperationDetail( _("move file system") ) ) ;
1858
operationdetail .get_last_child() .add_child(
1859
OperationDetail( _("new and old file system have the same position. Hence skipping this operation"),
1863
operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
1867
bool succes = false ;
1868
switch ( get_fs( partition_old .filesystem ) .move )
1870
case GParted::FS::NONE:
1872
case GParted::FS::GPARTED:
1874
if ( partition_new .test_overlap( partition_old ) )
1876
if ( copy_filesystem_simulation( partition_old, partition_new, operationdetail .get_last_child() ) )
1878
operationdetail .get_last_child() .add_child( OperationDetail( _("perform real move") ) ) ;
1881
succes = copy_filesystem( partition_old,
1883
operationdetail .get_last_child() .get_last_child(),
1886
operationdetail .get_last_child() .get_last_child()
1887
.set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
1890
rollback_transaction( partition_old,
1892
operationdetail .get_last_child(),
1895
check_repair_filesystem( partition_old, operationdetail ) ;
1900
succes = copy_filesystem( partition_old, partition_new, operationdetail .get_last_child() ) ;
1903
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
1904
case GParted::FS::LIBPARTED:
1905
succes = resize_move_filesystem_using_libparted( partition_old,
1907
operationdetail .get_last_child() ) ;
1910
case GParted::FS::EXTERNAL:
1911
succes = set_proper_filesystem( partition_new .filesystem ) &&
1912
p_filesystem ->move( partition_old
1914
, operationdetail .get_last_child()
1919
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
1923
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
1924
bool GParted_Core::resize_move_filesystem_using_libparted( const Partition & partition_old,
1925
const Partition & partition_new,
1926
OperationDetail & operationdetail )
1928
operationdetail .add_child( OperationDetail( _("using libparted"), STATUS_NONE ) ) ;
1930
bool return_value = false ;
1931
if ( open_device_and_disk( partition_old .device_path ) )
1933
PedFileSystem * fs = NULL ;
1934
PedGeometry * lp_geom = NULL ;
1936
lp_geom = ped_geometry_new( lp_device,
1937
partition_old .sector_start,
1938
partition_old .get_sector_length() ) ;
1941
fs = ped_file_system_open( lp_geom );
1945
lp_geom = ped_geometry_new( lp_device,
1946
partition_new .sector_start,
1947
partition_new .get_sector_length() ) ;
1949
return_value = ped_file_system_resize( fs, lp_geom, NULL ) && commit() ;
1951
ped_file_system_close( fs );
1955
close_device_and_disk() ;
1958
return return_value ;
1962
bool GParted_Core::resize( const Partition & partition_old,
1963
const Partition & partition_new,
1964
OperationDetail & operationdetail )
1966
if ( partition_old .sector_start != partition_new .sector_start )
1968
operationdetail .add_child( OperationDetail(
1969
_("resizing requires old and new start to be the same"), STATUS_ERROR, FONT_ITALIC ) ) ;
1974
bool succes = false ;
1975
if ( check_repair_filesystem( partition_new, operationdetail ) )
1979
if ( succes && partition_new .get_sector_length() < partition_old .get_sector_length() )
1980
succes = resize_filesystem( partition_old, partition_new, operationdetail ) ;
1983
succes = resize_move_partition( partition_old, partition_new, operationdetail ) ;
1985
//expand file system to fit exactly in partition
1986
if ( ! ( //Do not maximize file system if new size <= old
1987
( partition_new .get_sector_length() <= partition_old .get_sector_length() )
1988
|| ( check_repair_filesystem( partition_new, operationdetail )
1989
&& maximize_filesystem( partition_new, operationdetail )
2001
bool GParted_Core::resize_move_partition( const Partition & partition_old,
2002
const Partition & partition_new,
2003
OperationDetail & operationdetail )
2005
//i'm not too happy with this, but i think it is the correct way from a i18n POV
2013
MOVE_RIGHT_GROW = 5,
2014
MOVE_RIGHT_SHRINK = 6,
2016
MOVE_LEFT_SHRINK = 8
2018
Action action = NONE ;
2020
if ( partition_new .get_sector_length() > partition_old .get_sector_length() )
2022
else if ( partition_new .get_sector_length() < partition_old .get_sector_length() )
2025
if ( partition_new .sector_start > partition_old .sector_start &&
2026
partition_new .sector_end > partition_old .sector_end )
2027
action = action == GROW ? MOVE_RIGHT_GROW : action == SHRINK ? MOVE_RIGHT_SHRINK : MOVE_RIGHT ;
2028
else if ( partition_new .sector_start < partition_old .sector_start &&
2029
partition_new .sector_end < partition_old .sector_end )
2030
action = action == GROW ? MOVE_LEFT_GROW : action == SHRINK ? MOVE_LEFT_SHRINK : MOVE_LEFT ;
2032
Glib::ustring description ;
2036
description = _("resize/move partition") ;
2039
description = _("move partition to the right") ;
2042
description = _("move partition to the left") ;
2045
description = _("grow partition from %1 to %2") ;
2048
description = _("shrink partition from %1 to %2") ;
2050
case MOVE_RIGHT_GROW :
2051
description = _("move partition to the right and grow it from %1 to %2") ;
2053
case MOVE_RIGHT_SHRINK :
2054
description = _("move partition to the right and shrink it from %1 to %2") ;
2056
case MOVE_LEFT_GROW :
2057
description = _("move partition to the left and grow it from %1 to %2") ;
2059
case MOVE_LEFT_SHRINK :
2060
description = _("move partition to the left and shrink it from %1 to %2") ;
2064
if ( ! description .empty() && action != NONE && action != MOVE_LEFT && action != MOVE_RIGHT )
2065
description = String::ucompose( description,
2066
Utils::format_size( partition_old .get_sector_length(), partition_old .sector_size ),
2067
Utils::format_size( partition_new .get_sector_length(), partition_new .sector_size ) ) ;
2069
operationdetail .add_child( OperationDetail( description ) ) ;
2072
if ( action == NONE )
2074
operationdetail .get_last_child() .add_child(
2075
OperationDetail( _("new and old partition have the same size and position. Hence skipping this operation"),
2079
operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
2083
operationdetail .get_last_child() .add_child(
2085
String::ucompose( _("old start: %1"), partition_old .sector_start ) + "\n" +
2086
String::ucompose( _("old end: %1"), partition_old .sector_end ) + "\n" +
2087
String::ucompose( _("old size: %1 (%2)"),
2088
partition_old .get_sector_length(),
2089
Utils::format_size( partition_old .get_sector_length(), partition_old .sector_size ) ),
2093
//finally the actual resize/move
2094
bool return_value = false ;
2096
PedConstraint *constraint = NULL ;
2097
lp_partition = NULL ;
2099
//sometimes the lp_partition ->geom .start,end and length values display random numbers
2100
//after going out of the 'if ( lp_partition)' scope. That's why we use some variables here.
2101
Sector new_start = -1, new_end = -1 ;
2103
if ( open_device_and_disk( partition_old .device_path ) )
2105
if ( partition_old .type == GParted::TYPE_EXTENDED )
2106
lp_partition = ped_disk_extended_partition( lp_disk ) ;
2108
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition_old .get_sector() ) ;
2112
if ( (partition_new .alignment == ALIGN_STRICT)
2113
|| (partition_new .alignment == ALIGN_MEBIBYTE)
2114
|| partition_new .strict_start
2116
PedGeometry *geom = ped_geometry_new( lp_device,
2117
partition_new .sector_start,
2118
partition_new .get_sector_length() ) ;
2119
constraint = ped_constraint_exact( geom ) ;
2122
constraint = ped_constraint_any( lp_device ) ;
2126
if ( ped_disk_set_partition_geom( lp_disk,
2129
partition_new .sector_start,
2130
partition_new .sector_end ) )
2132
new_start = lp_partition ->geom .start ;
2133
new_end = lp_partition ->geom .end ;
2135
return_value = commit() ;
2138
ped_constraint_destroy( constraint );
2142
close_device_and_disk() ;
2147
operationdetail .get_last_child() .add_child(
2149
String::ucompose( _("new start: %1"), new_start ) + "\n" +
2150
String::ucompose( _("new end: %1"), new_end ) + "\n" +
2151
String::ucompose( _("new size: %1 (%2)"),
2152
new_end - new_start + 1,
2153
Utils::format_size( new_end - new_start + 1, partition_new .sector_size ) ),
2157
#ifndef USE_LIBPARTED_DMRAID
2158
//update dev mapper entry if partition is dmraid.
2160
if ( return_value && dmraid .is_dmraid_device( partition_new .device_path ) )
2162
//Open disk handle before and close after to prevent application crash.
2163
if ( open_device_and_disk( partition_new .device_path ) )
2165
return_value = dmraid .update_dev_map_entry( partition_new, operationdetail .get_last_child() ) ;
2166
close_device_and_disk() ;
2172
operationdetail .get_last_child() .set_status( return_value ? STATUS_SUCCES : STATUS_ERROR ) ;
2174
return return_value ;
2177
bool GParted_Core::resize_filesystem( const Partition & partition_old,
2178
const Partition & partition_new,
2179
OperationDetail & operationdetail,
2180
bool fill_partition )
2182
//by default 'grow' to accomodate expand_filesystem()
2183
GParted::FS::Support action = get_fs( partition_old .filesystem ) .grow ;
2185
if ( ! fill_partition )
2187
if ( partition_new .get_sector_length() < partition_old .get_sector_length() )
2189
operationdetail .add_child( OperationDetail( _("shrink file system") ) ) ;
2190
action = get_fs( partition_old .filesystem ) .shrink ;
2192
else if ( partition_new .get_sector_length() > partition_old .get_sector_length() )
2193
operationdetail .add_child( OperationDetail( _("grow file system") ) ) ;
2196
operationdetail .add_child( OperationDetail( _("resize file system") ) ) ;
2197
operationdetail .get_last_child() .add_child(
2199
_("new and old file system have the same size. Hence skipping this operation"),
2203
operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
2208
bool succes = false ;
2211
case GParted::FS::NONE:
2213
case GParted::FS::GPARTED:
2215
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
2216
case GParted::FS::LIBPARTED:
2217
succes = resize_move_filesystem_using_libparted( partition_old,
2219
operationdetail .get_last_child() ) ;
2222
case GParted::FS::EXTERNAL:
2223
succes = set_proper_filesystem( partition_new .filesystem ) &&
2224
p_filesystem ->resize( partition_new,
2225
operationdetail .get_last_child(),
2230
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2234
bool GParted_Core::maximize_filesystem( const Partition & partition, OperationDetail & operationdetail )
2236
operationdetail .add_child( OperationDetail( _("grow file system to fill the partition") ) ) ;
2238
if ( get_fs( partition .filesystem ) .grow == GParted::FS::NONE )
2240
operationdetail .get_last_child() .add_child(
2241
OperationDetail( _("growing is not available for this file system"),
2245
operationdetail .get_last_child() .set_status( STATUS_N_A ) ;
2249
return resize_filesystem( partition, partition, operationdetail, true ) ;
2252
bool GParted_Core::copy( const Partition & partition_src,
2253
Partition & partition_dst,
2254
Byte_Value min_size,
2255
OperationDetail & operationdetail )
2257
if ( partition_dst .get_byte_length() < partition_src .get_byte_length()
2258
&& partition_src .filesystem != FS_XFS // Permit copying to smaller xfs partition
2261
operationdetail .add_child( OperationDetail(
2262
_("the destination is smaller than the source partition"), STATUS_ERROR, FONT_ITALIC ) ) ;
2267
if ( check_repair_filesystem( partition_src, operationdetail ) )
2269
bool succes = true ;
2270
if ( partition_dst .status == GParted::STAT_COPY )
2272
/* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
2273
succes = create_partition( partition_dst, operationdetail, ( (min_size + (partition_dst .sector_size - 1)) / partition_dst .sector_size ) ) ;
2276
if ( succes && set_partition_type( partition_dst, operationdetail ) )
2278
operationdetail .add_child( OperationDetail(
2279
String::ucompose( _("copy file system of %1 to %2"),
2280
partition_src .get_path(),
2281
partition_dst .get_path() ) ) ) ;
2283
switch ( get_fs( partition_dst .filesystem ) .copy )
2285
case GParted::FS::GPARTED :
2286
succes = copy_filesystem( partition_src,
2288
operationdetail .get_last_child() ) ;
2291
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
2292
case GParted::FS::LIBPARTED :
2293
//FIXME: see if copying through libparted has any advantages
2297
case GParted::FS::EXTERNAL :
2298
succes = set_proper_filesystem( partition_dst .filesystem ) &&
2299
p_filesystem ->copy( partition_src .get_path(),
2300
partition_dst .get_path(),
2301
operationdetail .get_last_child() ) ;
2309
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2312
&& update_bootsector( partition_dst, operationdetail )
2313
&& ( //Do not maximize file system if destination size <= source
2314
( partition_dst .get_sector_length() <= partition_src .get_sector_length() )
2315
|| ( check_repair_filesystem( partition_dst, operationdetail )
2316
&& maximize_filesystem( partition_dst, operationdetail )
2326
bool GParted_Core::copy_filesystem_simulation( const Partition & partition_src,
2327
const Partition & partition_dst,
2328
OperationDetail & operationdetail )
2330
operationdetail .add_child( OperationDetail( _("perform read-only test") ) ) ;
2332
bool succes = copy_filesystem( partition_src, partition_dst, operationdetail .get_last_child(), true ) ;
2334
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2338
bool GParted_Core::copy_filesystem( const Partition & partition_src,
2339
const Partition & partition_dst,
2340
OperationDetail & operationdetail,
2344
return copy_filesystem( partition_src .device_path,
2345
partition_dst .device_path,
2346
partition_src .sector_start,
2347
partition_dst .sector_start,
2348
partition_src .sector_size,
2349
partition_dst .sector_size,
2350
partition_src .get_byte_length(),
2356
bool GParted_Core::copy_filesystem( const Partition & partition_src,
2357
const Partition & partition_dst,
2358
OperationDetail & operationdetail,
2359
Byte_Value & total_done )
2361
return copy_filesystem( partition_src .device_path,
2362
partition_dst .device_path,
2363
partition_src .sector_start,
2364
partition_dst .sector_start,
2365
partition_src .sector_size,
2366
partition_dst .sector_size,
2367
partition_src .get_byte_length(),
2373
bool GParted_Core::copy_filesystem( const Glib::ustring & src_device,
2374
const Glib::ustring & dst_device,
2377
Byte_Value src_sector_size,
2378
Byte_Value dst_sector_size,
2379
Byte_Value src_length,
2380
OperationDetail & operationdetail,
2382
Byte_Value & total_done )
2384
operationdetail .add_child( OperationDetail( _("using internal algorithm"), STATUS_NONE ) ) ;
2385
operationdetail .add_child( OperationDetail(
2386
String::ucompose( readonly ?
2387
/*TO TRANSLATORS: looks like read 1.00 MiB */
2389
/*TO TRANSLATORS: looks like copy 1.00 MiB */
2391
Utils::format_size( src_length, 1 ) ),
2394
operationdetail .add_child( OperationDetail( _("finding optimal block size"), STATUS_NONE ) ) ;
2396
Byte_Value benchmark_blocksize = readonly ? (2 * MEBIBYTE) : (1 * MEBIBYTE), N = (16 * MEBIBYTE) ;
2397
Byte_Value optimal_blocksize = benchmark_blocksize ;
2398
Sector offset_read = src_start ;
2399
Sector offset_write = dst_start ;
2401
//Handle situation where we need to perform the copy beginning
2402
// with the end of the partition and finishing with the start.
2403
if ( dst_start > src_start )
2405
offset_read += (src_length/src_sector_size) - (N/src_sector_size) ;
2406
/* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
2407
offset_write += ((src_length + (dst_sector_size - 1))/dst_sector_size) - (N/dst_sector_size) ;
2411
Byte_Value done = 0 ;
2413
double smallest_time = 1000000 ;
2414
bool succes = true ;
2416
//Benchmark copy times using different block sizes to determine optimal size
2418
llabs( done ) + N <= src_length &&
2419
benchmark_blocksize <= N )
2422
succes = copy_blocks( src_device,
2424
offset_read + (done / src_sector_size),
2425
offset_write + (done / dst_sector_size),
2427
benchmark_blocksize,
2428
operationdetail .get_last_child(),
2433
operationdetail .get_last_child() .get_last_child() .add_child( OperationDetail(
2434
String::ucompose( _("%1 seconds"), timer .elapsed() ), STATUS_NONE, FONT_ITALIC ) ) ;
2436
if ( timer .elapsed() <= smallest_time )
2438
smallest_time = timer .elapsed() ;
2439
optimal_blocksize = benchmark_blocksize ;
2441
benchmark_blocksize *= 2 ;
2443
if ( ( dst_start > src_start ) )
2450
operationdetail .get_last_child() .add_child( OperationDetail( String::ucompose(
2451
/*TO TRANSLATORS: looks like optimal block size is 1.00 MiB */
2452
_("optimal block size is %1"),
2453
Utils::format_size( optimal_blocksize, 1 ) ),
2456
if ( succes && llabs( done ) < src_length )
2457
succes = copy_blocks( src_device,
2459
src_start + ( dst_start > src_start ? 0 : (done / src_sector_size) ),
2460
dst_start + ( dst_start > src_start ? 0 : (done / dst_sector_size) ),
2461
src_length - llabs( done ),
2467
operationdetail .add_child( OperationDetail(
2468
String::ucompose( readonly ?
2469
/*TO TRANSLATORS: looks like 1.00 MiB (1048576 B) read */
2470
_("%1 (%2 B) read") :
2471
/*TO TRANSLATORS: looks like 1.00 MiB (1048576 B) copied */
2472
_("%1 (%2 B) copied"),
2473
Utils::format_size( total_done, 1 ), total_done ),
2478
void GParted_Core::rollback_transaction( const Partition & partition_src,
2479
const Partition & partition_dst,
2480
OperationDetail & operationdetail,
2481
Byte_Value total_done )
2483
if ( total_done > 0 )
2485
operationdetail .add_child( OperationDetail( _("roll back last transaction") ) ) ;
2487
//find out exactly which part of the file system was copied (and to where it was copied)..
2488
Partition temp_src = partition_src ;
2489
Partition temp_dst = partition_dst ;
2491
if ( partition_dst .sector_start > partition_src .sector_start )
2493
temp_src .sector_start = temp_src .sector_end - ( (total_done / temp_src .sector_size) - 1 ) ;
2494
temp_dst .sector_start = temp_dst .sector_end - ( (total_done / temp_dst .sector_size) - 1 ) ;
2498
temp_src .sector_end = temp_src .sector_start + ( (total_done / temp_src .sector_size) - 1 ) ;
2499
temp_dst .sector_end = temp_dst .sector_start + ( (total_done / temp_dst .sector_size) - 1 ) ;
2502
//and copy it back (NOTE the reversed dst and src)
2503
bool succes = copy_filesystem( temp_dst, temp_src, operationdetail .get_last_child() ) ;
2505
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2509
bool GParted_Core::check_repair_filesystem( const Partition & partition, OperationDetail & operationdetail )
2511
operationdetail .add_child( OperationDetail(
2513
/* TO TRANSLATORS: looks like check file system on /dev/sda5 for errors and (if possible) fix them */
2514
_("check file system on %1 for errors and (if possible) fix them"),
2515
partition .get_path() ) ) ) ;
2517
bool succes = false ;
2518
switch ( get_fs( partition .filesystem ) .check )
2520
case GParted::FS::NONE:
2521
operationdetail .get_last_child() .add_child(
2522
OperationDetail( _("checking is not available for this file system"),
2526
operationdetail .get_last_child() .set_status( STATUS_N_A ) ;
2530
case GParted::FS::GPARTED:
2532
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
2533
case GParted::FS::LIBPARTED:
2536
case GParted::FS::EXTERNAL:
2537
succes = set_proper_filesystem( partition .filesystem ) &&
2538
p_filesystem ->check_repair( partition, operationdetail .get_last_child() ) ;
2543
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2547
bool GParted_Core::set_partition_type( const Partition & partition, OperationDetail & operationdetail )
2549
operationdetail .add_child( OperationDetail(
2550
String::ucompose( _("set partition type on %1"), partition .get_path() ) ) ) ;
2552
bool return_value = false ;
2554
if ( open_device_and_disk( partition .device_path ) )
2556
PedFileSystemType * fs_type =
2557
ped_file_system_type_get( Utils::get_filesystem_string( partition .filesystem ) .c_str() ) ;
2559
//If not found, and FS is linux-swap, then try linux-swap(v1)
2560
if ( ! fs_type && Utils::get_filesystem_string( partition .filesystem ) == "linux-swap" )
2561
fs_type = ped_file_system_type_get( "linux-swap(v1)" ) ;
2563
//If not found, and FS is linux-swap, then try linux-swap(new)
2564
if ( ! fs_type && Utils::get_filesystem_string( partition .filesystem ) == "linux-swap" )
2565
fs_type = ped_file_system_type_get( "linux-swap(new)" ) ;
2567
//default is Linux (83)
2569
fs_type = ped_file_system_type_get( "ext2" ) ;
2573
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
2575
if ( lp_partition &&
2576
ped_partition_set_system( lp_partition, fs_type ) &&
2579
operationdetail .get_last_child() .add_child(
2580
OperationDetail( String::ucompose( _("new partition type: %1"),
2581
lp_partition ->fs_type ->name ),
2585
return_value = true ;
2589
close_device_and_disk() ;
2592
operationdetail .get_last_child() .set_status( return_value ? STATUS_SUCCES : STATUS_ERROR ) ;
2593
return return_value ;
2596
void GParted_Core::set_progress_info( Byte_Value total,
2598
const Glib::Timer & timer,
2599
OperationDetail & operationdetail,
2602
operationdetail .fraction = done / static_cast<double>( total ) ;
2604
std::time_t time_remaining = Utils::round( (total - done) / ( done / timer .elapsed() ) ) ;
2606
operationdetail .progress_text =
2607
String::ucompose( readonly ?
2608
/*TO TRANSLATORS: looks like 1.00 MiB of 16.00 MiB read (00:01:59 remaining) */
2609
_("%1 of %2 read (%3 remaining)") :
2610
/*TO TRANSLATORS: looks like 1.00 MiB of 16.00 MiB copied (00:01:59 remaining) */
2611
_("%1 of %2 copied (%3 remaining)"),
2612
Utils::format_size( done, 1 ),
2613
Utils::format_size( total,1 ),
2614
Utils::format_time( time_remaining) ) ;
2616
operationdetail .set_description(
2617
String::ucompose( readonly ?
2618
/*TO TRANSLATORS: looks like 1.00 MiB of 16.00 MiB read */
2619
_("%1 of %2 read") :
2620
/*TO TRANSLATORS: looks like 1.00 MiB of 16.00 MiB copied */
2621
_("%1 of %2 copied"),
2622
Utils::format_size( done, 1 ), Utils::format_size( total, 1 ) ),
2626
bool GParted_Core::copy_blocks( const Glib::ustring & src_device,
2627
const Glib::ustring & dst_device,
2631
Byte_Value blocksize,
2632
OperationDetail & operationdetail,
2634
Byte_Value & total_done )
2636
if ( blocksize > length )
2637
blocksize = length ;
2640
operationdetail .add_child( OperationDetail(
2641
/*TO TRANSLATORS: looks like read 16.00 MiB using a block size of 1.00 MiB */
2642
String::ucompose( _("read %1 using a block size of %2"), Utils::format_size( length, 1 ),
2643
Utils::format_size( blocksize, 1 ) ) ) ) ;
2645
operationdetail .add_child( OperationDetail(
2646
/*TO TRANSLATORS: looks like copy 16.00 MiB using a block size of 1.00 MiB */
2647
String::ucompose( _("copy %1 using a block size of %2"), Utils::format_size( length, 1 ),
2648
Utils::format_size( blocksize, 1 ) ) ) ) ;
2650
Byte_Value done = length % blocksize ;
2652
bool succes = false ;
2653
PedDevice *lp_device_src = ped_device_get( src_device .c_str() );
2654
PedDevice *lp_device_dst = src_device != dst_device ? ped_device_get( dst_device .c_str() ) : lp_device_src ;
2656
if ( lp_device_src && lp_device_dst && ped_device_open( lp_device_src ) && ped_device_open( lp_device_dst ) )
2658
Byte_Value src_sector_size = lp_device_src ->sector_size ;
2659
Byte_Value dst_sector_size = lp_device_dst ->sector_size ;
2661
//Handle situation where we need to perform the copy beginning
2662
// with the end of the partition and finishing with the start.
2663
if ( dst_start > src_start )
2665
blocksize -= 2*blocksize ;
2667
src_start += ( (length / src_sector_size) - 1 ) ;
2668
/* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
2669
dst_start += ( ((length + (dst_sector_size - 1))/ dst_sector_size) - 1 ) ;
2672
Glib::ustring error_message ;
2673
buf = static_cast<char *>( malloc( llabs( blocksize ) ) ) ;
2676
ped_device_sync( lp_device_dst ) ;
2680
succes = copy_block( lp_device_src,
2690
//add an empty sub which we will constantly update in the loop
2691
operationdetail .get_last_child() .add_child( OperationDetail( "", STATUS_NONE ) ) ;
2693
Glib::Timer timer_progress_timeout, timer_total ;
2694
while( succes && llabs( done ) < length )
2696
succes = copy_block( lp_device_src,
2698
src_start + (done / src_sector_size),
2699
dst_start + (done / dst_sector_size),
2706
if ( timer_progress_timeout .elapsed() >= 0.5 )
2708
set_progress_info( length,
2709
llabs( done + blocksize ),
2711
operationdetail .get_last_child() .get_last_child(),
2714
timer_progress_timeout .reset() ;
2717
//set progress bar current info on completion
2718
set_progress_info( length,
2721
operationdetail .get_last_child() .get_last_child(),
2727
error_message = Glib::strerror( errno ) ;
2729
//reset fraction to -1 to make room for a new one (or a pulsebar)
2730
operationdetail .get_last_child() .get_last_child() .fraction = -1 ;
2733
operationdetail .get_last_child() .get_last_child() .set_description(
2734
String::ucompose( readonly ?
2735
/*TO TRANSLATORS: looks like 1.00 MiB of 16.00 MiB read */
2736
_("%1 of %2 read") :
2737
/*TO TRANSLATORS: looks like 1.00 MiB of 16.00 MiB copied */
2738
_("%1 of %2 copied"),
2739
Utils::format_size( llabs( done ), 1 ),
2740
Utils::format_size( length, 1 ) ),
2743
if ( ! succes && ! error_message .empty() )
2744
operationdetail .get_last_child() .add_child(
2745
OperationDetail( error_message, STATUS_NONE, FONT_ITALIC ) ) ;
2747
total_done += llabs( done ) ;
2749
//close and destroy the devices..
2750
ped_device_close( lp_device_src ) ;
2751
ped_device_destroy( lp_device_src ) ;
2753
if ( src_device != dst_device )
2755
ped_device_close( lp_device_dst ) ;
2756
ped_device_destroy( lp_device_dst ) ;
2760
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2764
bool GParted_Core::copy_block( PedDevice * lp_device_src,
2765
PedDevice * lp_device_dst,
2768
Byte_Value block_length,
2769
Glib::ustring & error_message,
2772
Byte_Value sector_size_src = lp_device_src ->sector_size ;
2773
Byte_Value sector_size_dst = lp_device_dst ->sector_size ;
2775
//Handle case where src and dst sector sizes are different.
2776
// E.g., 5 sectors x 512 bytes/sector = ??? 2048 byte sectors
2777
Sector num_blocks_src = (llabs(block_length) + (sector_size_src - 1) ) / sector_size_src ;
2778
Sector num_blocks_dst = (llabs(block_length) + (sector_size_dst - 1) ) / sector_size_dst ;
2780
//Handle situation where we are performing copy operation beginning
2781
// with the end of the partition and finishing with the start.
2782
if ( block_length < 0 )
2784
block_length = llabs( block_length ) ;
2785
offset_src -= ( (block_length / sector_size_src) - 1 ) ;
2786
/* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
2787
offset_dst -= ( ( (block_length + (sector_size_dst - 1)) / sector_size_dst) - 1 ) ;
2790
if ( block_length != 0 )
2792
if ( ped_device_read( lp_device_src, buf, offset_src, num_blocks_src ) )
2794
if ( readonly || ped_device_write( lp_device_dst, buf, offset_dst, num_blocks_dst ) )
2797
error_message = String::ucompose( _("Error while writing block at sector %1"), offset_dst ) ;
2800
error_message = String::ucompose( _("Error while reading block at sector %1"), offset_src ) ;
2806
bool GParted_Core::calibrate_partition( Partition & partition, OperationDetail & operationdetail )
2808
if ( partition .type == TYPE_PRIMARY || partition .type == TYPE_LOGICAL || partition .type == TYPE_EXTENDED )
2810
operationdetail .add_child( OperationDetail( String::ucompose( _("calibrate %1"), partition .get_path() ) ) ) ;
2812
bool succes = false ;
2813
if ( open_device_and_disk( partition .device_path ) )
2815
if ( partition .type == GParted::TYPE_EXTENDED )
2816
lp_partition = ped_disk_extended_partition( lp_disk ) ;
2818
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
2820
if ( lp_partition )//FIXME: add check to see if lp_partition ->type matches partition .type..
2822
partition .add_path( get_partition_path( lp_partition ) ) ;
2824
partition .sector_start = lp_partition ->geom .start ;
2825
partition .sector_end = lp_partition ->geom .end ;
2827
operationdetail .get_last_child() .add_child(
2829
String::ucompose( _("path: %1"), partition .get_path() ) + "\n" +
2830
String::ucompose( _("start: %1"), partition .sector_start ) + "\n" +
2831
String::ucompose( _("end: %1"), partition .sector_end ) + "\n" +
2832
String::ucompose( _("size: %1 (%2)"),
2833
partition .get_sector_length(),
2834
Utils::format_size( partition .get_sector_length(), partition .sector_size ) ),
2840
close_device_and_disk() ;
2843
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2846
else //nothing to calibrate...
2850
bool GParted_Core::calculate_exact_geom( const Partition & partition_old,
2851
Partition & partition_new,
2852
OperationDetail & operationdetail )
2854
operationdetail .add_child( OperationDetail(
2855
String::ucompose( _("calculate new size and position of %1"), partition_new .get_path() ) ) ) ;
2857
operationdetail .get_last_child() .add_child(
2859
String::ucompose( _("requested start: %1"), partition_new .sector_start ) + "\n" +
2860
String::ucompose( _("requested end: %1"), partition_new .sector_end ) + "\n" +
2861
String::ucompose( _("requested size: %1 (%2)"),
2862
partition_new .get_sector_length(),
2863
Utils::format_size( partition_new .get_sector_length(), partition_new .sector_size ) ),
2867
bool succes = false ;
2868
if ( open_device_and_disk( partition_old .device_path ) )
2870
lp_partition = NULL ;
2872
if ( partition_old .type == GParted::TYPE_EXTENDED )
2873
lp_partition = ped_disk_extended_partition( lp_disk ) ;
2875
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition_old .get_sector() ) ;
2879
PedConstraint *constraint = NULL ;
2880
constraint = ped_constraint_any( lp_device ) ;
2884
//FIXME: if we insert a weird partitionnew geom here (e.g. start > end)
2885
//ped_disk_set_partition_geom() will still return true (althoug an lp exception is written
2886
//to stdout.. see if this also affect create_partition and resize_move_partition
2887
//sended a patch to fix this to libparted list. will probably be in 1.7.2
2888
if ( ped_disk_set_partition_geom( lp_disk,
2891
partition_new .sector_start,
2892
partition_new .sector_end ) )
2894
partition_new .sector_start = lp_partition ->geom .start ;
2895
partition_new .sector_end = lp_partition ->geom .end ;
2899
ped_constraint_destroy( constraint );
2903
close_device_and_disk() ;
2908
operationdetail .get_last_child() .add_child(
2910
String::ucompose( _("new start: %1"), partition_new .sector_start ) + "\n" +
2911
String::ucompose( _("new end: %1"), partition_new .sector_end ) + "\n" +
2912
String::ucompose( _("new size: %1 (%2)"),
2913
partition_new .get_sector_length(),
2914
Utils::format_size( partition_new .get_sector_length(), partition_new .sector_size ) ),
2918
#ifndef USE_LIBPARTED_DMRAID
2919
//Update dev mapper entry if partition is dmraid.
2921
if ( succes && dmraid .is_dmraid_device( partition_new .device_path ) )
2923
//Open disk handle before and close after to prevent application crash.
2924
if ( open_device_and_disk( partition_new .device_path ) )
2926
succes = dmraid .update_dev_map_entry( partition_new, operationdetail .get_last_child() ) ;
2927
close_device_and_disk() ;
2933
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
2937
bool GParted_Core::set_proper_filesystem( const FILESYSTEM & filesystem )
2939
delete p_filesystem;
2941
switch( filesystem )
2943
case FS_BTRFS : p_filesystem = new btrfs() ; break ;
2944
case FS_EXFAT : p_filesystem = new exfat() ; break ;
2945
case FS_EXT2 : p_filesystem = new ext2() ; break ;
2946
case FS_EXT3 : p_filesystem = new ext3() ; break ;
2947
case FS_EXT4 : p_filesystem = new ext4() ; break ;
2948
case FS_LINUX_SWAP : p_filesystem = new linux_swap() ; break ;
2949
case FS_FAT16 : p_filesystem = new fat16() ; break ;
2950
case FS_FAT32 : p_filesystem = new fat32() ; break ;
2951
case FS_NTFS : p_filesystem = new ntfs() ; break ;
2952
case FS_REISERFS : p_filesystem = new reiserfs() ; break ;
2953
case FS_REISER4 : p_filesystem = new reiser4() ; break ;
2954
case FS_XFS : p_filesystem = new xfs() ; break ;
2955
case FS_JFS : p_filesystem = new jfs() ; break ;
2956
case FS_HFS : p_filesystem = new hfs() ; break ;
2957
case FS_HFSPLUS : p_filesystem = new hfsplus() ; break ;
2958
case FS_UFS : p_filesystem = new ufs() ; break ;
2959
default : p_filesystem = NULL ;
2962
return p_filesystem ;
2965
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
2966
bool GParted_Core::erase_filesystem_signatures( const Partition & partition )
2968
bool return_value = false ;
2970
if ( open_device_and_disk( partition .device_path ) )
2972
lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
2974
if ( lp_partition && ped_file_system_clobber( & lp_partition ->geom ) )
2976
//file systems not yet supported by libparted
2977
if ( ped_device_open( lp_device ) )
2979
//reiser4 stores "ReIsEr4" at sector 128 with a sector size of 512 bytes
2980
// FIXME writing block of partially uninitialized bytes (security/privacy)
2981
return_value = ped_geometry_write( & lp_partition ->geom, "0000000", (65536 / lp_device ->sector_size), 1 ) ;
2983
ped_device_close( lp_device ) ;
2987
close_device_and_disk() ;
2990
return return_value ;
2994
bool GParted_Core::update_bootsector( const Partition & partition, OperationDetail & operationdetail )
2996
//only for ntfs atm...
2997
//FIXME: this should probably be done in the fs classes...
2998
if ( partition .filesystem == FS_NTFS )
3000
//The NTFS file system stores a value in the boot record called the
3001
// Number of Hidden Sectors. This value must match the partition start
3002
// sector number in order for Windows to boot from the file system.
3003
// For more details, refer to the NTFS Volume Boot Record at:
3004
// http://www.geocities.com/thestarman3/asm/mbr/NTFSBR.htm
3006
operationdetail .add_child( OperationDetail(
3007
/*TO TRANSLATORS: update boot sector of ntfs file system on /dev/sdd1 */
3008
String::ucompose( _("update boot sector of %1 file system on %2"),
3009
Utils::get_filesystem_string( partition .filesystem ),
3010
partition .get_path() ) ) ) ;
3012
//convert start sector to hex string
3013
std::stringstream ss ;
3014
ss << std::hex << partition .sector_start ;
3015
Glib::ustring hex = ss .str() ;
3017
//fill with zeros and reverse...
3018
hex .insert( 0, 8 - hex .length(), '0' ) ;
3019
Glib::ustring reversed_hex ;
3020
for ( int t = 6 ; t >= 0 ; t -=2 )
3021
reversed_hex .append( hex .substr( t, 2 ) ) ;
3023
//convert reversed hex codes into ascii characters
3025
for ( unsigned int k = 0; (k < 4 && k < (reversed_hex .length() / 2)); k++ )
3027
Glib::ustring tmp_hex = "0x" + reversed_hex .substr( k * 2, 2 ) ;
3028
buf[k] = (char)( std::strtol( tmp_hex .c_str(), NULL, 16 ) ) ;
3031
//write new Number of Hidden Sectors value into NTFS boot sector at offset 0x1C
3032
Glib::ustring error_message = "" ;
3033
std::ofstream dev_file ;
3034
dev_file .open( partition .get_path() .c_str(), std::ios::out | std::ios::binary ) ;
3035
if ( dev_file .is_open() )
3037
dev_file .seekp( 0x1C ) ;
3038
if ( dev_file .good() )
3040
dev_file .write( buf, 4 ) ;
3041
if ( dev_file .bad() )
3043
/*TO TRANSLATORS: looks like Error trying to write to boot sector in /dev/sdd1 */
3044
error_message = String::ucompose( _("Error trying to write to boot sector in %1"), partition .get_path() ) ;
3049
/*TO TRANSLATORS: looks like Error trying to seek to position 0x1C in /dev/sdd1 */
3050
error_message = String::ucompose( _("Error trying to seek to position 0x1c in %1"), partition .get_path() ) ;
3052
dev_file .close( ) ;
3056
/*TO TRANSLATORS: looks like Error trying to open /dev/sdd1 */
3057
error_message = String::ucompose( _("Error trying to open %1"), partition .get_path() ) ;
3060
//append error messages if any found
3061
bool succes = true ;
3062
if ( ! error_message .empty() )
3065
error_message += "\n" ;
3066
/*TO TRANSLATORS: looks like Failed to set the number of hidden sectors to 05ab4f00 in the ntfs boot record. */
3067
error_message += String::ucompose( _("Failed to set the number of hidden sectors to %1 in the NTFS boot record."), reversed_hex ) ;
3068
error_message += "\n" ;
3069
error_message += String::ucompose( _("You might try the following command to correct the problem:"), reversed_hex ) ;
3070
error_message += "\n" ;
3071
error_message += String::ucompose( "echo %1 | xxd -r -p | dd conv=notrunc of=%2 bs=1 seek=28", reversed_hex, partition .get_path() ) ;
3072
operationdetail .get_last_child() .add_child( OperationDetail( error_message, STATUS_NONE, FONT_ITALIC ) ) ;
3075
operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
3082
bool GParted_Core::open_device( const Glib::ustring & device_path )
3084
lp_device = ped_device_get( device_path .c_str() );
3089
bool GParted_Core::open_device_and_disk( const Glib::ustring & device_path, bool strict )
3094
if ( open_device( device_path ) )
3096
lp_disk = ped_disk_new( lp_device );
3098
//if ! disk and writeable it's probably a HD without disklabel.
3099
//We return true here and deal with them in GParted_Core::get_devices
3100
if ( lp_disk || ( ! strict && ! lp_device ->read_only ) )
3103
close_device_and_disk() ;
3109
void GParted_Core::close_disk()
3112
ped_disk_destroy( lp_disk ) ;
3117
void GParted_Core::close_device_and_disk()
3122
ped_device_destroy( lp_device ) ;
3127
bool GParted_Core::commit()
3129
bool succes = ped_disk_commit_to_dev( lp_disk ) ;
3131
succes = commit_to_os( 10 ) && succes ;
3136
bool GParted_Core::commit_to_os( std::time_t timeout )
3139
#ifndef USE_LIBPARTED_DMRAID
3141
if ( dmraid .is_dmraid_device( lp_disk ->dev ->path ) )
3146
succes = ped_disk_commit_to_os( lp_disk ) ;
3147
#ifndef HAVE_LIBPARTED_2_2_0_PLUS
3148
//Work around to try to alleviate problems caused by
3149
// bug #604298 - Failure to inform kernel of partition changes
3150
// If not successful the first time, try one more time.
3154
succes = ped_disk_commit_to_os( lp_disk ) ;
3157
#ifndef USE_LIBPARTED_DMRAID
3161
settle_device( timeout ) ;
3166
void GParted_Core::settle_device( std::time_t timeout )
3168
if ( ! Glib::find_program_in_path( "udevsettle" ) .empty() )
3169
Utils::execute_command( "udevsettle --timeout=" + Utils::num_to_str( timeout ) ) ;
3170
else if ( ! Glib::find_program_in_path( "udevadm" ) .empty() )
3171
Utils::execute_command( "udevadm settle --timeout=" + Utils::num_to_str( timeout ) ) ;
3176
PedExceptionOption GParted_Core::ped_exception_handler( PedException * e )
3178
std::cout << e ->message << std::endl ;
3180
libparted_messages .push_back( e->message ) ;
3182
return PED_EXCEPTION_UNHANDLED ;
3185
GParted_Core::~GParted_Core()
3187
delete p_filesystem;