~ubuntu-branches/ubuntu/saucy/gparted/saucy

« back to all changes in this revision

Viewing changes to .pc/03_drop-swraid.patch/src/GParted_Core.cc

  • Committer: Package Import Robot
  • Author(s): Phillip Susi
  • Date: 2012-11-29 13:55:11 UTC
  • Revision ID: package-import@ubuntu.com-20121129135511-1q9x7pr6p1yso4gi
Tags: 0.12.1-2
debian/patches/drop-swraid.patch: Upstream patch to remove broken and
uneeded swraid support that was causing errors with mdadm devices
(LP: #1074606) (Closes: #697872).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2004 Bart 'plors' Hakvoort
 
2
 * Copyright (C) 2008, 2009, 2010, 2011, 2012 Curtis Gedak
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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.
 
17
 */
 
18
 
 
19
#include "../include/Win_GParted.h"
 
20
#include "../include/GParted_Core.h"
 
21
#include "../include/DMRaid.h"
 
22
#include "../include/SWRaid.h"
 
23
#include "../include/FS_Info.h"
 
24
#include "../include/LVM2_PV_Info.h"
 
25
#include "../include/OperationCopy.h"
 
26
#include "../include/OperationCreate.h"
 
27
#include "../include/OperationDelete.h"
 
28
#include "../include/OperationFormat.h"
 
29
#include "../include/OperationResizeMove.h"
 
30
#include "../include/OperationChangeUUID.h"
 
31
#include "../include/OperationLabelPartition.h"
 
32
#include "../include/Proc_Partitions_Info.h"
 
33
 
 
34
#include "../include/btrfs.h"
 
35
#include "../include/exfat.h"
 
36
#include "../include/ext2.h"
 
37
#include "../include/ext3.h"
 
38
#include "../include/ext4.h"
 
39
#include "../include/fat16.h"
 
40
#include "../include/fat32.h"
 
41
#include "../include/linux_swap.h"
 
42
#include "../include/lvm2_pv.h"
 
43
#include "../include/reiserfs.h"
 
44
#include "../include/nilfs2.h"
 
45
#include "../include/ntfs.h"
 
46
#include "../include/xfs.h"
 
47
#include "../include/jfs.h"
 
48
#include "../include/hfs.h"
 
49
#include "../include/hfsplus.h"
 
50
#include "../include/reiser4.h"
 
51
#include "../include/ufs.h"
 
52
#include <set>
 
53
#include <cerrno>
 
54
#include <cstring>
 
55
#include <sys/statvfs.h>
 
56
#include <sys/types.h>
 
57
#include <sys/stat.h>
 
58
#include <unistd.h>
 
59
#include <dirent.h>
 
60
#include <mntent.h>
 
61
#include <gtkmm/messagedialog.h>
 
62
 
 
63
std::vector<Glib::ustring> libparted_messages ; //see ped_exception_handler()
 
64
 
 
65
namespace GParted
 
66
{
 
67
 
 
68
GParted_Core::GParted_Core() 
 
69
{
 
70
        lp_device = NULL ;
 
71
        lp_disk = NULL ;
 
72
        lp_partition = NULL ;
 
73
        p_filesystem = NULL ;
 
74
        thread_status_message = "" ;
 
75
 
 
76
        ped_exception_set_handler( ped_exception_handler ) ; 
 
77
 
 
78
        //get valid flags ...
 
79
        for ( PedPartitionFlag flag = ped_partition_flag_next( static_cast<PedPartitionFlag>( NULL ) ) ;
 
80
              flag ;
 
81
              flag = ped_partition_flag_next( flag ) )
 
82
                flags .push_back( flag ) ;
 
83
        
 
84
        //throw libpartedversion to the stdout to see which version is actually used.
 
85
        std::cout << "======================" << std::endl ;
 
86
        std::cout << "libparted : " << ped_get_version() << std::endl ;
 
87
        std::cout << "======================" << std::endl ;
 
88
 
 
89
        //initialize file system list
 
90
        find_supported_filesystems() ;
 
91
}
 
92
 
 
93
void GParted_Core::find_supported_filesystems()
 
94
{
 
95
        std::map< FILESYSTEM, FileSystem * >::iterator f ;
 
96
 
 
97
        // TODO: determine whether it is safe to initialize this only once
 
98
        for ( f = FILESYSTEM_MAP .begin() ; f != FILESYSTEM_MAP .end() ; f++ ) {
 
99
                if ( f ->second )
 
100
                        delete f ->second ;
 
101
        }
 
102
 
 
103
        FILESYSTEM_MAP .clear() ;
 
104
 
 
105
        FILESYSTEM_MAP[ FS_BTRFS ]      = new btrfs() ;
 
106
        FILESYSTEM_MAP[ FS_EXFAT ]      = new exfat() ;
 
107
        FILESYSTEM_MAP[ FS_EXT2 ]       = new ext2() ;
 
108
        FILESYSTEM_MAP[ FS_EXT3 ]       = new ext3() ;
 
109
        FILESYSTEM_MAP[ FS_EXT4 ]       = new ext4() ;
 
110
        FILESYSTEM_MAP[ FS_FAT16 ]      = new fat16() ;
 
111
        FILESYSTEM_MAP[ FS_FAT32 ]      = new fat32() ;
 
112
        FILESYSTEM_MAP[ FS_HFS ]        = new hfs() ;
 
113
        FILESYSTEM_MAP[ FS_HFSPLUS ]    = new hfsplus() ;
 
114
        FILESYSTEM_MAP[ FS_JFS ]        = new jfs() ;
 
115
        FILESYSTEM_MAP[ FS_LINUX_SWAP ] = new linux_swap() ;
 
116
        FILESYSTEM_MAP[ FS_LVM2_PV ]    = new lvm2_pv() ;
 
117
        FILESYSTEM_MAP[ FS_NILFS2 ]     = new nilfs2() ;
 
118
        FILESYSTEM_MAP[ FS_NTFS ]       = new ntfs() ;
 
119
        FILESYSTEM_MAP[ FS_REISER4 ]    = new reiser4() ;
 
120
        FILESYSTEM_MAP[ FS_REISERFS ]   = new reiserfs() ;
 
121
        FILESYSTEM_MAP[ FS_UFS ]        = new ufs() ;
 
122
        FILESYSTEM_MAP[ FS_XFS ]        = new xfs() ;
 
123
        FILESYSTEM_MAP[ FS_LUKS ]       = NULL ;
 
124
        FILESYSTEM_MAP[ FS_UNKNOWN ]    = NULL ;
 
125
 
 
126
        FILESYSTEMS .clear() ;
 
127
 
 
128
        FS fs_notsupp;
 
129
        for ( f = FILESYSTEM_MAP .begin() ; f != FILESYSTEM_MAP .end() ; f++ ) {
 
130
                if ( f ->second )
 
131
                        FILESYSTEMS .push_back( f ->second ->get_filesystem_support() ) ;
 
132
                else {
 
133
                        fs_notsupp .filesystem = f ->first ;
 
134
                        FILESYSTEMS .push_back( fs_notsupp ) ;
 
135
                }
 
136
        }
 
137
}
 
138
 
 
139
void GParted_Core::set_user_devices( const std::vector<Glib::ustring> & user_devices ) 
 
140
{
 
141
        this ->device_paths = user_devices ;
 
142
        this ->probe_devices = ! user_devices .size() ;
 
143
}
 
144
        
 
145
void GParted_Core::set_devices( std::vector<Device> & devices )
 
146
{
 
147
        devices .clear() ;
 
148
        Device temp_device ;
 
149
        Proc_Partitions_Info pp_info( true ) ;  //Refresh cache of proc partition information
 
150
        FS_Info fs_info( true ) ;  //Refresh cache of file system information
 
151
        DMRaid dmraid( true ) ;    //Refresh cache of dmraid device information
 
152
        SWRaid swraid( true ) ;    //Refresh cache of swraid device information
 
153
        LVM2_PV_Info lvm2_pv_info( true ) ;     //Refresh cache of LVM2 PV information
 
154
        
 
155
        init_maps() ;
 
156
        
 
157
        //only probe if no devices were specified as arguments..
 
158
        if ( probe_devices )
 
159
        {
 
160
                device_paths .clear() ;
 
161
 
 
162
                //FIXME:  When libparted bug 194 is fixed, remove code to read:
 
163
                //           /proc/partitions
 
164
                //        This was a problem with no floppy drive yet BIOS indicated one existed.
 
165
                //        http://parted.alioth.debian.org/cgi-bin/trac.cgi/ticket/194
 
166
                //
 
167
                //try to find all available devices if devices exist in /proc/partitions
 
168
                std::vector<Glib::ustring> temp_devices = pp_info .get_device_paths() ;
 
169
                if ( ! temp_devices .empty() )
 
170
                {
 
171
                        //Try to find all devices in /proc/partitions
 
172
                        for (unsigned int k=0; k < temp_devices .size(); k++)
 
173
                        {
 
174
                                /*TO TRANSLATORS: looks like Scanning /dev/sda */
 
175
                                set_thread_status_message( String::ucompose ( _("Scanning %1"), temp_devices[ k ] ) ) ;
 
176
                                ped_device_get( temp_devices[ k ] .c_str() ) ;
 
177
                        }
 
178
 
 
179
                        //Try to find all swraid devices
 
180
                        if (swraid .is_swraid_supported() ) {
 
181
                                std::vector<Glib::ustring> swraid_devices ;
 
182
                                swraid .get_devices( swraid_devices ) ;
 
183
                                for ( unsigned int k=0; k < swraid_devices .size(); k++ ) {
 
184
                                        set_thread_status_message( String::ucompose ( _("Scanning %1"), swraid_devices[k] ) ) ;
 
185
                                        ped_device_get( swraid_devices[k] .c_str() ) ;
 
186
                                }
 
187
                        }
 
188
 
 
189
                        //Try to find all dmraid devices
 
190
                        if (dmraid .is_dmraid_supported() ) {
 
191
                                std::vector<Glib::ustring> dmraid_devices ;
 
192
                                dmraid .get_devices( dmraid_devices ) ;
 
193
                                for ( unsigned int k=0; k < dmraid_devices .size(); k++ ) {
 
194
                                        set_thread_status_message( String::ucompose ( _("Scanning %1"), dmraid_devices[k] ) ) ;
 
195
#ifndef USE_LIBPARTED_DMRAID
 
196
                                        dmraid .create_dev_map_entries( dmraid_devices[k] ) ;
 
197
                                        settle_device( 1 ) ;
 
198
#endif
 
199
                                        ped_device_get( dmraid_devices[k] .c_str() ) ;
 
200
                                }
 
201
                        }
 
202
                }
 
203
                else
 
204
                {
 
205
                        //No devices found in /proc/partitions so use libparted to probe devices
 
206
                        ped_device_probe_all();
 
207
                }
 
208
 
 
209
                lp_device = ped_device_get_next( NULL );
 
210
                while ( lp_device ) 
 
211
                {
 
212
                        //only add this device if we can read the first sector (which means it's a real device)
 
213
                        char * buf = static_cast<char *>( malloc( lp_device ->sector_size ) ) ;
 
214
                        if ( buf )
 
215
                        {
 
216
                                /*TO TRANSLATORS: looks like Confirming /dev/sda */ 
 
217
                                set_thread_status_message( String::ucompose ( _("Confirming %1"), lp_device ->path ) ) ;
 
218
                                if ( ped_device_open( lp_device ) )
 
219
                                {
 
220
#ifdef HAVE_LIBPARTED_2_2_0_PLUS
 
221
                                        //Devices with sector sizes of 512 bytes and higher are supported
 
222
                                        if ( ped_device_read( lp_device, buf, 0, 1 ) )
 
223
                                                device_paths .push_back( lp_device ->path ) ;
 
224
#else
 
225
                                        //Only devices with sector sizes of 512 bytes are well supported
 
226
                                        if ( lp_device ->sector_size != 512 )
 
227
                                        {
 
228
                                                /*TO TRANSLATORS: looks like  Ignoring device /dev/sde with logical sector size of 2048 bytes. */
 
229
                                                Glib::ustring msg = String::ucompose ( _("Ignoring device %1 with logical sector size of %2 bytes."), lp_device ->path, lp_device ->sector_size ) ;
 
230
                                                msg += "\n" ;
 
231
                                                msg += _("GParted requires libparted version 2.2 or higher to support devices with sector sizes larger than 512 bytes.") ;
 
232
                                                std::cout << msg << std::endl << std::endl ;
 
233
                                        }
 
234
                                        else
 
235
                                        {
 
236
                                                if ( ped_device_read( lp_device, buf, 0, 1 ) )
 
237
                                                        device_paths .push_back( lp_device ->path ) ;
 
238
                                        }
 
239
#endif
 
240
                                        ped_device_close( lp_device ) ;
 
241
                                }
 
242
                                free( buf ) ;
 
243
                        }
 
244
                        lp_device = ped_device_get_next( lp_device ) ;
 
245
                }
 
246
                close_device_and_disk() ;
 
247
 
 
248
                std::sort( device_paths .begin(), device_paths .end() ) ;
 
249
        }
 
250
#ifndef USE_LIBPARTED_DMRAID
 
251
        else
 
252
        {
 
253
                //Device paths were passed in on the command line.
 
254
 
 
255
                //Ensure that dmraid device entries are created
 
256
                for ( unsigned int t = 0 ; t < device_paths .size() ; t++ ) 
 
257
                {
 
258
                        if ( dmraid .is_dmraid_supported() &&
 
259
                             dmraid .is_dmraid_device( device_paths[t] ) )
 
260
                        {
 
261
                                dmraid .create_dev_map_entries( dmraid .get_dmraid_name( device_paths [t] ) ) ;
 
262
                        }
 
263
                }
 
264
        }
 
265
#endif
 
266
 
 
267
        for ( unsigned int t = 0 ; t < device_paths .size() ; t++ ) 
 
268
        {
 
269
                /*TO TRANSLATORS: looks like Searching /dev/sda partitions */ 
 
270
                set_thread_status_message( String::ucompose ( _("Searching %1 partitions"), device_paths[ t ] ) ) ;
 
271
                if ( open_device_and_disk( device_paths[ t ], false ) )
 
272
                {
 
273
                        temp_device .Reset() ;
 
274
 
 
275
                        //device info..
 
276
                        temp_device .add_path( device_paths[ t ] ) ;
 
277
                        temp_device .add_paths( pp_info .get_alternate_paths( temp_device .get_path() ) ) ;
 
278
 
 
279
                        temp_device .model      =       lp_device ->model ;
 
280
                        temp_device .length     =       lp_device ->length ;
 
281
                        temp_device .sector_size        =       lp_device ->sector_size ;
 
282
                        temp_device .heads      =       lp_device ->bios_geom .heads ;
 
283
                        temp_device .sectors    =       lp_device ->bios_geom .sectors ;
 
284
                        temp_device .cylinders  =       lp_device ->bios_geom .cylinders ;
 
285
                        temp_device .cylsize    =       temp_device .heads * temp_device .sectors ; 
 
286
                
 
287
                        //make sure cylsize is at least 1 MiB
 
288
                        if ( temp_device .cylsize < (MEBIBYTE / temp_device .sector_size) )
 
289
                                temp_device .cylsize = (MEBIBYTE / temp_device .sector_size) ;
 
290
                                
 
291
                        //normal harddisk
 
292
                        if ( lp_disk )
 
293
                        {
 
294
                                temp_device .disktype = lp_disk ->type ->name ;
 
295
                                temp_device .max_prims = ped_disk_get_max_primary_partition_count( lp_disk ) ;
 
296
                                
 
297
                                set_device_partitions( temp_device ) ;
 
298
                                set_mountpoints( temp_device .partitions ) ;
 
299
                                set_used_sectors( temp_device .partitions ) ;
 
300
                        
 
301
                                if ( temp_device .highest_busy )
 
302
                                {
 
303
                                        temp_device .readonly = ! commit_to_os( 1 ) ;
 
304
                                        //Clear libparted messages.  Typically these are:
 
305
                                        //  The kernel was unable to re-read the partition table...
 
306
                                        libparted_messages .clear() ;
 
307
                                }
 
308
                        }
 
309
                        //harddisk without disklabel
 
310
                        else
 
311
                        {
 
312
                                temp_device .disktype =
 
313
                                                /* TO TRANSLATORS:  unrecognized
 
314
                                                 * means that the partition table for this
 
315
                                                 * disk device is unknown or not recognized.
 
316
                                                 */
 
317
                                                _("unrecognized") ;
 
318
                                temp_device .max_prims = -1 ;
 
319
                                
 
320
                                Partition partition_temp ;
 
321
                                partition_temp .Set_Unallocated( temp_device .get_path(),
 
322
                                                                 0,
 
323
                                                                 temp_device .length - 1,
 
324
                                                                 temp_device .sector_size,
 
325
                                                                 false );
 
326
                                //Place libparted messages in this unallocated partition
 
327
                                partition_temp .messages .insert( partition_temp .messages .end(),
 
328
                                                                  libparted_messages. begin(),
 
329
                                                                  libparted_messages .end() ) ;
 
330
                                libparted_messages .clear() ;
 
331
                                temp_device .partitions .push_back( partition_temp );
 
332
                        }
 
333
                                        
 
334
                        devices .push_back( temp_device ) ;
 
335
                        
 
336
                        close_device_and_disk() ;
 
337
                }
 
338
        }
 
339
 
 
340
        //clear leftover information... 
 
341
        //NOTE that we cannot clear mountinfo since it might be needed in get_all_mountpoints()
 
342
        set_thread_status_message("") ;
 
343
        fstab_info .clear() ;
 
344
}
 
345
 
 
346
// runs gpart on the specified parameter
 
347
void GParted_Core::guess_partition_table(const Device & device, Glib::ustring &buff)
 
348
{
 
349
        int pid, stdoutput, stderror;
 
350
        std::vector<std::string> argvproc, envpproc;
 
351
        gunichar tmp;
 
352
 
 
353
        //Get the char string of the sector_size
 
354
        std::ostringstream ssIn;
 
355
    ssIn << device.sector_size;
 
356
    Glib::ustring str_ssize = ssIn.str();
 
357
 
 
358
        //Build the command line
 
359
        argvproc.push_back("gpart");
 
360
        argvproc.push_back(device.get_path());
 
361
        argvproc.push_back("-s");
 
362
        argvproc.push_back(str_ssize);
 
363
 
 
364
        envpproc .push_back( "LC_ALL=C" ) ;
 
365
        envpproc .push_back( "PATH=" + Glib::getenv( "PATH" ) ) ;
 
366
 
 
367
        Glib::spawn_async_with_pipes(Glib::get_current_dir(), argvproc,
 
368
                envpproc, Glib::SPAWN_SEARCH_PATH, sigc::slot<void>(),
 
369
                &pid, NULL, &stdoutput, &stderror);
 
370
 
 
371
        this->iocOutput=Glib::IOChannel::create_from_fd(stdoutput);
 
372
 
 
373
        while(this->iocOutput->read(tmp)==Glib::IO_STATUS_NORMAL)
 
374
        {
 
375
                buff+=tmp;
 
376
        }
 
377
        this->iocOutput->close();
 
378
 
 
379
        return;
 
380
}
 
381
 
 
382
void GParted_Core::set_thread_status_message( Glib::ustring msg )
 
383
{
 
384
        //Remember to clear status message when finished with thread.
 
385
        thread_status_message = msg ;
 
386
}
 
387
 
 
388
Glib::ustring GParted_Core::get_thread_status_message( )
 
389
{
 
390
        return thread_status_message ;
 
391
}
 
392
 
 
393
bool GParted_Core::snap_to_cylinder( const Device & device, Partition & partition, Glib::ustring & error ) 
 
394
{
 
395
        Sector diff = 0;
 
396
 
 
397
        //Determine if partition size is less than half a disk cylinder
 
398
        bool less_than_half_cylinder = false;
 
399
        if ( ( partition .sector_end - partition .sector_start ) < ( device .cylsize / 2 ) )
 
400
                less_than_half_cylinder = true;
 
401
 
 
402
        if ( partition.type == TYPE_LOGICAL ||
 
403
             partition.sector_start == device .sectors
 
404
           )
 
405
        {
 
406
                //Must account the relative offset between:
 
407
                // (A) the Extended Boot Record sector and the next track of the
 
408
                //     logical partition (usually 63 sectors), and
 
409
                // (B) the Master Boot Record sector and the next track of the first
 
410
                //     primary partition
 
411
                diff = (partition .sector_start - device .sectors) % device .cylsize ;
 
412
        }
 
413
        else if ( partition.sector_start == 34 )
 
414
        {
 
415
                // (C) the GUID Partition Table (GPT) and the start of the data
 
416
                //     partition at sector 34
 
417
                diff = (partition .sector_start - 34 ) % device .cylsize ;
 
418
        }
 
419
        else
 
420
        {
 
421
                diff = partition .sector_start % device .cylsize ;
 
422
        }
 
423
        if ( diff && ! partition .strict_start  )
 
424
        {
 
425
                if ( diff < ( device .cylsize / 2 ) || less_than_half_cylinder )
 
426
                        partition .sector_start -= diff ;
 
427
                else
 
428
                        partition .sector_start += (device .cylsize - diff ) ;
 
429
        }
 
430
 
 
431
        diff = (partition .sector_end +1) % device .cylsize ;
 
432
        if ( diff )
 
433
        {
 
434
                if ( diff < ( device .cylsize / 2 ) && ! less_than_half_cylinder )
 
435
                        partition .sector_end -= diff ;
 
436
                else
 
437
                        partition .sector_end += (device .cylsize - diff ) ;
 
438
        }
 
439
 
 
440
        return true ;
 
441
}
 
442
 
 
443
bool GParted_Core::snap_to_mebibyte( const Device & device, Partition & partition, Glib::ustring & error ) 
 
444
{
 
445
        Sector diff = 0;
 
446
        if ( partition .sector_start < 2 || partition .type == TYPE_LOGICAL )
 
447
        {
 
448
                //Must account the relative offset between:
 
449
                // (A) the Master Boot Record sector and the first primary/extended partition, and
 
450
                // (B) the Extended Boot Record sector and the logical partition
 
451
 
 
452
                //If strict_start is set then do not adjust sector start.
 
453
                //If this partition is not simply queued for a reformat then
 
454
                //  add space minimum to force alignment to next mebibyte.
 
455
                if (   (! partition .strict_start)
 
456
                    && (partition .free_space_before == 0)
 
457
                    && ( partition .status != STAT_FORMATTED)
 
458
                   )
 
459
                {
 
460
                        //Unless specifically told otherwise, the Linux kernel considers extended
 
461
                        //  boot records to be two sectors long, in order to "leave room for LILO".
 
462
                        partition .sector_start += 2 ;
 
463
                }
 
464
        }
 
465
 
 
466
        //Calculate difference offset from Mebibyte boundary
 
467
        diff = Sector(partition .sector_start % ( MEBIBYTE / partition .sector_size ));
 
468
 
 
469
        //Align start sector only if permitted to change start sector
 
470
        if ( diff && (   (! partition .strict_start)
 
471
                      || (   partition .strict_start
 
472
                          && (   partition .status == STAT_NEW
 
473
                              || partition .status == STAT_COPY
 
474
                             )
 
475
                         )
 
476
                     )
 
477
           )
 
478
        {
 
479
                partition .sector_start += ( (MEBIBYTE / partition .sector_size) - diff) ;
 
480
 
 
481
                //If this is an extended partition then check to see if sufficient space is
 
482
                //  available for any following logical partition Extended Boot Record
 
483
                if ( partition .type == TYPE_EXTENDED )
 
484
                {
 
485
                        //Locate the extended partition that contains the logical partitions.
 
486
                        int index_extended = -1 ;
 
487
                        for ( unsigned int t = 0 ; t < device .partitions .size() ; t++ )
 
488
                        {
 
489
                                if ( device .partitions[ t ] .type == TYPE_EXTENDED )
 
490
                                        index_extended = t ;
 
491
                        }
 
492
 
 
493
                        //If there is logical partition that starts less than 2 sectors
 
494
                        //  from the start of this partition, then reserve a mebibyte for the EBR.
 
495
                        if ( index_extended != -1 )
 
496
                        {
 
497
                                for ( unsigned int t = 0; t < device .partitions[ index_extended ] .logicals .size(); t++ )
 
498
                                {
 
499
                                        if (   ( device .partitions[ index_extended ] .logicals[ t ] .type == TYPE_LOGICAL )
 
500
                                            && ( (  (  device .partitions[ index_extended ] .logicals[ t ] .sector_start )
 
501
                                                  - ( partition .sector_start )
 
502
                                                 )
 
503
                                                 //Unless specifically told otherwise, the Linux kernel considers extended
 
504
                                                 //  boot records to be two sectors long, in order to "leave room for LILO".
 
505
                                                 < 2
 
506
                                               )
 
507
                                           )
 
508
                                        {
 
509
                                                partition .sector_start -= (MEBIBYTE / partition .sector_size) ;
 
510
                                        }
 
511
                                }
 
512
                        }
 
513
                }
 
514
        }
 
515
 
 
516
        //Align end sector
 
517
        diff = (partition .sector_end + 1) % ( MEBIBYTE / partition .sector_size);
 
518
        if ( diff )
 
519
                partition .sector_end -= diff ;
 
520
 
 
521
        //If this is a logical partition not at end of drive then check to see if space is
 
522
        //  required for a following logical partition Extended Boot Record
 
523
        if ( partition .type == TYPE_LOGICAL )
 
524
        {
 
525
                //Locate the extended partition that contains the logical partitions.
 
526
                int index_extended = -1 ;
 
527
                for ( unsigned int t = 0 ; t < device .partitions .size() ; t++ )
 
528
                {
 
529
                        if ( device .partitions[ t ] .type == TYPE_EXTENDED )
 
530
                                index_extended = t ;
 
531
                }
 
532
 
 
533
                //If there is a following logical partition that starts less than 2 sectors from
 
534
                //  the end of this partition, then reserve at least a mebibyte for the EBR.
 
535
                if ( index_extended != -1 )
 
536
                {
 
537
                        for ( unsigned int t = 0; t < device .partitions[ index_extended ] .logicals .size(); t++ )
 
538
                        {
 
539
                                if (   ( device .partitions[ index_extended ] .logicals[ t ] .type == TYPE_LOGICAL )
 
540
                                    && ( device .partitions[ index_extended ] .logicals[ t ] .sector_start > partition .sector_end )
 
541
                                    && ( ( device .partitions[ index_extended ] .logicals[ t ] .sector_start - partition .sector_end )
 
542
                                           //Unless specifically told otherwise, the Linux kernel considers extended
 
543
                                           //  boot records to be two sectors long, in order to "leave room for LILO".
 
544
                                         < 2
 
545
                                       )
 
546
                                   )
 
547
                                        partition .sector_end -= ( MEBIBYTE / partition .sector_size ) ;
 
548
                        }
 
549
                }
 
550
        }
 
551
 
 
552
        //If this is a primary or an extended partition and the partition overlaps
 
553
        //  the start of the next primary or extended partition then subtract a
 
554
        //  mebibyte from the end of the partition to address the overlap.
 
555
        if ( partition .type == TYPE_PRIMARY || partition .type == TYPE_EXTENDED )
 
556
        {
 
557
                for ( unsigned int t = 0 ; t < device .partitions .size() ; t++ )
 
558
                {
 
559
                        if (   (   device .partitions[ t ] .type == TYPE_PRIMARY
 
560
                                || device .partitions[ t ] .type == TYPE_EXTENDED
 
561
                               )
 
562
                            && ( device .partitions[ t ] .sector_start > partition .sector_start )
 
563
                            && ( device .partitions[ t ] .sector_start <= partition .sector_end )
 
564
                           )
 
565
                                partition .sector_end -= ( MEBIBYTE / partition .sector_size );
 
566
                }
 
567
        }
 
568
 
 
569
        //If this is a GPT partition table and the partition ends less than 34 sectors
 
570
        //  from the end of the device, then reserve at least a mebibyte for the
 
571
        //  backup partition table
 
572
        if (    device .disktype == "gpt"
 
573
            && ( ( device .length - partition .sector_end ) < 34 )
 
574
           )
 
575
        {
 
576
                partition .sector_end -= ( MEBIBYTE / partition .sector_size ) ;
 
577
        }
 
578
 
 
579
        return true ;
 
580
}
 
581
 
 
582
bool GParted_Core::snap_to_alignment( const Device & device, Partition & partition, Glib::ustring & error )
 
583
{
 
584
        bool rc = true ;
 
585
 
 
586
        if ( partition .alignment == ALIGN_CYLINDER )
 
587
                rc = snap_to_cylinder( device, partition, error ) ;
 
588
        else if ( partition .alignment == ALIGN_MEBIBYTE )
 
589
                rc = snap_to_mebibyte( device, partition, error ) ;
 
590
 
 
591
        //Ensure that partition start and end are not beyond the ends of the disk device
 
592
        if ( partition .sector_start < 0 )
 
593
                partition .sector_start = 0 ;
 
594
        if ( partition .sector_end > device .length )
 
595
                partition .sector_end = device .length - 1 ;
 
596
 
 
597
        //do some basic checks on the partition
 
598
        if ( partition .get_sector_length() <= 0 )
 
599
        {
 
600
                error = String::ucompose(
 
601
                                /* TO TRANSLATORS:  looks like   A partition cannot have a length of -1 sectors */
 
602
                                _("A partition cannot have a length of %1 sectors"),
 
603
                                partition .get_sector_length() ) ;
 
604
                return false ;
 
605
        }
 
606
 
 
607
        if ( partition .get_sector_length() < partition .sectors_used )
 
608
        {
 
609
                error = String::ucompose(
 
610
                                /* TO TRANSLATORS: looks like   A partition with used sectors (2048) greater than its length (1536) is not valid */
 
611
                                _("A partition with used sectors (%1) greater than its length (%2) is not valid"),
 
612
                                partition .sectors_used,
 
613
                                partition .get_sector_length() ) ;
 
614
                return false ;
 
615
        }
 
616
 
 
617
        //FIXME: it would be perfect if we could check for overlapping with adjacent partitions as well,
 
618
        //however, finding the adjacent partitions is not as easy as it seems and at this moment all the dialogs
 
619
        //already perform these checks. A perfect 'fixme-later' ;)
 
620
 
 
621
        return rc ;
 
622
}
 
623
 
 
624
bool GParted_Core::apply_operation_to_disk( Operation * operation )
 
625
{
 
626
        bool succes = false ;
 
627
        libparted_messages .clear() ;
 
628
 
 
629
        if ( calibrate_partition( operation ->partition_original, operation ->operation_detail ) )
 
630
                switch ( operation ->type )
 
631
                {            
 
632
                        case OPERATION_DELETE:
 
633
                                succes = Delete( operation ->partition_original, operation ->operation_detail ) ;
 
634
                                break ;
 
635
                        case OPERATION_CHECK:
 
636
                                succes = check_repair_filesystem( operation ->partition_original, operation ->operation_detail ) &&
 
637
                                         maximize_filesystem( operation ->partition_original, operation ->operation_detail ) ;
 
638
                                break ;
 
639
                        case OPERATION_CREATE:
 
640
                                succes = create( operation ->device, 
 
641
                                                 operation ->partition_new,
 
642
                                                 operation ->operation_detail ) ;
 
643
                                break ;
 
644
                        case OPERATION_RESIZE_MOVE:
 
645
                                //in case the to be resized/moved partition was a 'copy of..', we need a real path...
 
646
                                operation ->partition_new .add_path( operation ->partition_original .get_path(), true ) ;
 
647
                                succes = resize_move( operation ->device,
 
648
                                                      operation ->partition_original,
 
649
                                                      operation ->partition_new,
 
650
                                                      operation ->operation_detail ) ;
 
651
                                break ;
 
652
                        case OPERATION_FORMAT:
 
653
                                succes = format( operation ->partition_new, operation ->operation_detail ) ;
 
654
                                break ;
 
655
                        case OPERATION_COPY:
 
656
                        //FIXME: in case of a new partition we should make sure the new partition is >= the source partition... 
 
657
                        //i think it's best to do this in the dialog_paste
 
658
                                succes = ( operation ->partition_original .type == TYPE_UNALLOCATED || 
 
659
                                           calibrate_partition( operation ->partition_new, operation ->operation_detail ) ) &&
 
660
                                
 
661
                                         calibrate_partition( static_cast<OperationCopy*>( operation ) ->partition_copied,
 
662
                                                              operation ->operation_detail ) &&
 
663
 
 
664
                                         copy( static_cast<OperationCopy*>( operation ) ->partition_copied,
 
665
                                               operation ->partition_new,
 
666
                                               static_cast<OperationCopy*>( operation ) ->partition_copied .get_byte_length(),
 
667
                                               operation ->operation_detail ) ;
 
668
                                break ;
 
669
                        case OPERATION_LABEL_PARTITION:
 
670
                                succes = label_partition( operation ->partition_new, operation ->operation_detail ) ;
 
671
                                break ;
 
672
                        case OPERATION_CHANGE_UUID:
 
673
                                succes = change_uuid( operation ->partition_new, operation ->operation_detail ) ;
 
674
                                break ;
 
675
                }
 
676
 
 
677
        if ( libparted_messages .size() > 0 )
 
678
        {
 
679
                operation ->operation_detail .add_child( OperationDetail( _("libparted messages"), STATUS_INFO ) ) ;
 
680
 
 
681
                for ( unsigned int t = 0 ; t < libparted_messages .size() ; t++ )
 
682
                        operation ->operation_detail .get_last_child() .add_child(
 
683
                                OperationDetail( libparted_messages[ t ], STATUS_NONE, FONT_ITALIC ) ) ;
 
684
        }
 
685
 
 
686
        return succes ;
 
687
}
 
688
 
 
689
bool GParted_Core::set_disklabel( const Glib::ustring & device_path, const Glib::ustring & disklabel ) 
 
690
{
 
691
        bool return_value = false ;
 
692
        
 
693
        if ( open_device_and_disk( device_path, false ) )
 
694
        {
 
695
                PedDiskType *type = NULL ;
 
696
                type = ped_disk_type_get( disklabel .c_str() ) ;
 
697
                
 
698
                if ( type )
 
699
                {
 
700
                        lp_disk = ped_disk_new_fresh( lp_device, type );
 
701
                
 
702
                        return_value = commit() ;
 
703
                }
 
704
                
 
705
                close_device_and_disk() ;
 
706
        }
 
707
 
 
708
#ifndef USE_LIBPARTED_DMRAID
 
709
        //delete and recreate disk entries if dmraid
 
710
        DMRaid dmraid ;
 
711
        if ( return_value && dmraid .is_dmraid_device( device_path ) )
 
712
        {
 
713
                dmraid .purge_dev_map_entries( device_path ) ;
 
714
                dmraid .create_dev_map_entries( device_path ) ;
 
715
        }
 
716
#endif
 
717
 
 
718
        return return_value ;   
 
719
}
 
720
        
 
721
bool GParted_Core::toggle_flag( const Partition & partition, const Glib::ustring & flag, bool state ) 
 
722
{
 
723
        bool succes = false ;
 
724
 
 
725
        if ( open_device_and_disk( partition .device_path ) )
 
726
        {
 
727
                lp_partition = NULL ;
 
728
                if ( partition .type == GParted::TYPE_EXTENDED )
 
729
                        lp_partition = ped_disk_extended_partition( lp_disk ) ;
 
730
                else
 
731
                        lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
 
732
        
 
733
                if ( lp_partition )
 
734
                {
 
735
                        PedPartitionFlag lp_flag = ped_partition_flag_get_by_name( flag .c_str() ) ;
 
736
 
 
737
                        if ( lp_flag > 0 && ped_partition_set_flag( lp_partition, lp_flag, state ) )
 
738
                                succes = commit() ;
 
739
                }
 
740
        
 
741
                close_device_and_disk() ;
 
742
        }
 
743
 
 
744
        return succes ;
 
745
}
 
746
 
 
747
const std::vector<FS> & GParted_Core::get_filesystems() const 
 
748
{
 
749
        return FILESYSTEMS ;
 
750
}
 
751
 
 
752
const FS & GParted_Core::get_fs( GParted::FILESYSTEM filesystem ) const 
 
753
{
 
754
        unsigned int unknown ;
 
755
 
 
756
        unknown = FILESYSTEMS .size() ;
 
757
        for ( unsigned int t = 0 ; t < FILESYSTEMS .size() ; t++ )
 
758
        {
 
759
                if ( FILESYSTEMS[ t ] .filesystem == filesystem )
 
760
                        return FILESYSTEMS[ t ] ;
 
761
                else if ( FILESYSTEMS[ t ] .filesystem == FS_UNKNOWN )
 
762
                        unknown = t ;
 
763
        }
 
764
 
 
765
        if ( unknown == FILESYSTEMS .size() ) {
 
766
                // This shouldn't happen, but just in case...
 
767
                static FS fs;
 
768
                fs .filesystem = FS_UNKNOWN ;
 
769
                return fs ;
 
770
        } else
 
771
                return FILESYSTEMS[ unknown ] ;
 
772
}
 
773
 
 
774
std::vector<Glib::ustring> GParted_Core::get_disklabeltypes() 
 
775
{
 
776
        std::vector<Glib::ustring> disklabeltypes ;
 
777
        
 
778
        //msdos should be first in the list
 
779
        disklabeltypes .push_back( "msdos" ) ;
 
780
        
 
781
         PedDiskType *disk_type ;
 
782
         for ( disk_type = ped_disk_type_get_next( NULL ) ; disk_type ; disk_type = ped_disk_type_get_next( disk_type ) ) 
 
783
                 if ( Glib::ustring( disk_type->name ) != "msdos" )
 
784
                        disklabeltypes .push_back( disk_type->name ) ;
 
785
 
 
786
         return disklabeltypes ;
 
787
}
 
788
 
 
789
std::vector<Glib::ustring> GParted_Core::get_all_mountpoints() 
 
790
{
 
791
        std::vector<Glib::ustring> mountpoints ;
 
792
 
 
793
        for ( iter_mp = mount_info .begin() ; iter_mp != mount_info .end() ; ++iter_mp )
 
794
                mountpoints .insert( mountpoints .end(), iter_mp ->second .begin(), iter_mp ->second .end() ) ;
 
795
 
 
796
        return mountpoints ;
 
797
}
 
798
        
 
799
std::map<Glib::ustring, bool> GParted_Core::get_available_flags( const Partition & partition ) 
 
800
{
 
801
        std::map<Glib::ustring, bool> flag_info ;
 
802
 
 
803
        if ( open_device_and_disk( partition .device_path ) )
 
804
        {
 
805
                lp_partition = NULL ;
 
806
                if ( partition .type == GParted::TYPE_EXTENDED )
 
807
                        lp_partition = ped_disk_extended_partition( lp_disk ) ;
 
808
                else
 
809
                        lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
 
810
        
 
811
                if ( lp_partition )
 
812
                {
 
813
                        for ( unsigned int t = 0 ; t < flags .size() ; t++ )
 
814
                                if ( ped_partition_is_flag_available( lp_partition, flags[ t ] ) )
 
815
                                        flag_info[ ped_partition_flag_get_name( flags[ t ] ) ] =
 
816
                                                ped_partition_get_flag( lp_partition, flags[ t ] ) ;
 
817
                }
 
818
        
 
819
                close_device_and_disk() ;
 
820
        }
 
821
 
 
822
        return flag_info ;
 
823
}
 
824
        
 
825
Glib::ustring GParted_Core::get_libparted_version() 
 
826
{
 
827
        return ped_get_version() ;
 
828
}
 
829
 
 
830
//private functions...
 
831
 
 
832
void GParted_Core::init_maps() 
 
833
{
 
834
        mount_info .clear() ;
 
835
        fstab_info .clear() ;
 
836
 
 
837
        read_mountpoints_from_file( "/proc/mounts", mount_info ) ;
 
838
        read_mountpoints_from_file_swaps( "/proc/swaps", mount_info ) ;
 
839
        read_mountpoints_from_file( "/etc/mtab", mount_info ) ;
 
840
        read_mountpoints_from_file( "/etc/fstab", fstab_info ) ;
 
841
        
 
842
        //sort the mount points and remove duplicates.. (no need to do this for fstab_info)
 
843
        for ( iter_mp = mount_info .begin() ; iter_mp != mount_info .end() ; ++iter_mp )
 
844
        {
 
845
                std::sort( iter_mp ->second .begin(), iter_mp ->second .end() ) ;
 
846
                
 
847
                iter_mp ->second .erase( 
 
848
                                std::unique( iter_mp ->second .begin(), iter_mp ->second .end() ),
 
849
                                iter_mp ->second .end() ) ;
 
850
        }
 
851
}
 
852
 
 
853
void GParted_Core::read_mountpoints_from_file(
 
854
        const Glib::ustring & filename,
 
855
        std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
 
856
{
 
857
        FS_Info fs_info ;  //Use cache of file system information
 
858
 
 
859
        FILE* fp = setmntent( filename .c_str(), "r" ) ;
 
860
 
 
861
        if ( fp == NULL )
 
862
                return ;
 
863
 
 
864
        struct mntent* p = NULL ;
 
865
 
 
866
        while ( (p = getmntent(fp)) != NULL )
 
867
        {
 
868
                Glib::ustring node = p->mnt_fsname ;
 
869
 
 
870
                Glib::ustring uuid = Utils::regexp_label( node, "^UUID=(.*)" ) ;
 
871
                if ( ! uuid .empty() )
 
872
                        node = fs_info .get_path_by_uuid( uuid ) ;
 
873
 
 
874
                Glib::ustring label = Utils::regexp_label( node, "^LABEL=(.*)" ) ;
 
875
                if ( ! label .empty() )
 
876
                        node = fs_info .get_path_by_label( label ) ;
 
877
 
 
878
                if ( ! node .empty() )
 
879
                {
 
880
                        Glib::ustring mountpoint = p->mnt_dir ;
 
881
 
 
882
                        //Only add node path(s) if mount point exists
 
883
                        if ( file_test( mountpoint, Glib::FILE_TEST_EXISTS ) )
 
884
                        {
 
885
                                map[ node ] .push_back( mountpoint ) ;
 
886
 
 
887
                                //If node is a symbolic link (e.g., /dev/root)
 
888
                                //  then find real path and add entry
 
889
                                if ( file_test( node, Glib::FILE_TEST_IS_SYMLINK ) )
 
890
                                {
 
891
                                        char c_str[4096+1] ;
 
892
                                        //FIXME: it seems realpath is very unsafe to use (manpage)...
 
893
                                        if ( realpath( node .c_str(), c_str ) != NULL )
 
894
                                                map[ c_str ] .push_back( mountpoint ) ;
 
895
                                }
 
896
                        }
 
897
                }
 
898
        }
 
899
 
 
900
        endmntent( fp ) ;
 
901
}
 
902
 
 
903
void GParted_Core::read_mountpoints_from_file_swaps(
 
904
        const Glib::ustring & filename,
 
905
        std::map< Glib::ustring, std::vector<Glib::ustring> > & map )
 
906
{
 
907
        std::string line ;
 
908
        std::string node ;
 
909
        
 
910
        std::ifstream file( filename .c_str() ) ;
 
911
        if ( file )
 
912
        {
 
913
                while ( getline( file, line ) )
 
914
                {
 
915
                        node = Utils::regexp_label( line, "^(/[^ ]+)" ) ;
 
916
                        if ( node .size() > 0 )
 
917
                                map[ node ] .push_back( "" /* no mountpoint for swap */ ) ;
 
918
                }
 
919
                file .close() ;
 
920
        }
 
921
}
 
922
 
 
923
Glib::ustring GParted_Core::get_partition_path( PedPartition * lp_partition )
 
924
{
 
925
        char * lp_path;  //we have to free the result of ped_partition_get_path()
 
926
        Glib::ustring partition_path = "Partition path not found";
 
927
 
 
928
        lp_path = ped_partition_get_path(lp_partition);
 
929
        if ( lp_path != NULL )
 
930
        {
 
931
                partition_path = lp_path;
 
932
                free(lp_path);
 
933
        }
 
934
 
 
935
#ifndef USE_LIBPARTED_DMRAID
 
936
        //Ensure partition path name is compatible with dmraid
 
937
        DMRaid dmraid;   //Use cache of dmraid device information
 
938
        if (   dmraid .is_dmraid_supported()
 
939
            && dmraid .is_dmraid_device( partition_path )
 
940
           )
 
941
        {
 
942
                partition_path = dmraid .make_path_dmraid_compatible(partition_path);
 
943
        }
 
944
#endif
 
945
 
 
946
        return partition_path ;
 
947
}
 
948
 
 
949
void GParted_Core::set_device_partitions( Device & device ) 
 
950
{
 
951
        int EXT_INDEX = -1 ;
 
952
        Proc_Partitions_Info pp_info ; //Use cache of proc partitions information
 
953
        FS_Info fs_info ;  //Use cache of file system information
 
954
#ifndef USE_LIBPARTED_DMRAID
 
955
        DMRaid dmraid ;    //Use cache of dmraid device information
 
956
#endif
 
957
        LVM2_PV_Info lvm2_pv_info ;
 
958
 
 
959
        //clear partitions
 
960
        device .partitions .clear() ;
 
961
 
 
962
        lp_partition = ped_disk_next_partition( lp_disk, NULL ) ;
 
963
        while ( lp_partition )
 
964
        {
 
965
                libparted_messages .clear() ;
 
966
                partition_temp .Reset() ;
 
967
                bool partition_is_busy = false ;
 
968
                GParted::FILESYSTEM filesystem ;
 
969
 
 
970
                //Retrieve partition path
 
971
                Glib::ustring partition_path = get_partition_path( lp_partition );
 
972
 
 
973
                switch ( lp_partition ->type )
 
974
                {
 
975
                        case PED_PARTITION_NORMAL:
 
976
                        case PED_PARTITION_LOGICAL:
 
977
                                filesystem = get_filesystem() ;
 
978
#ifndef USE_LIBPARTED_DMRAID
 
979
                                //Handle dmraid devices differently because the minor number might not
 
980
                                //  match the last number of the partition filename as shown by "ls -l /dev/mapper"
 
981
                                //  This mismatch causes incorrect identification of busy partitions in ped_partition_is_busy(). 
 
982
                                if ( dmraid .is_dmraid_device( device .get_path() ) )
 
983
                                {
 
984
                                        //Try device_name + partition_number
 
985
                                        iter_mp = mount_info .find( device .get_path() + Utils::num_to_str( lp_partition ->num ) ) ;
 
986
                                        if ( iter_mp != mount_info .end() )
 
987
                                                partition_is_busy = true ;
 
988
                                        //Try device_name + p + partition_number
 
989
                                        iter_mp = mount_info .find( device .get_path() + "p" + Utils::num_to_str( lp_partition ->num ) ) ;
 
990
                                        if ( iter_mp != mount_info .end() )
 
991
                                                partition_is_busy = true ;
 
992
                                }
 
993
                                else
 
994
#endif
 
995
                                        partition_is_busy = ped_partition_is_busy( lp_partition ) ||
 
996
                                                            ( filesystem == GParted::FS_LVM2_PV && lvm2_pv_info .has_active_lvs( partition_path ) ) ;
 
997
 
 
998
                                partition_temp .Set( device .get_path(),
 
999
                                                     partition_path,
 
1000
                                                     lp_partition ->num,
 
1001
                                                     lp_partition ->type == 0 ? GParted::TYPE_PRIMARY : GParted::TYPE_LOGICAL,
 
1002
                                                     filesystem,
 
1003
                                                     lp_partition ->geom .start,
 
1004
                                                     lp_partition ->geom .end,
 
1005
                                                     device .sector_size,
 
1006
                                                     lp_partition ->type,
 
1007
                                                     partition_is_busy ) ;
 
1008
 
 
1009
                                partition_temp .add_paths( pp_info .get_alternate_paths( partition_temp .get_path() ) ) ;
 
1010
                                set_flags( partition_temp ) ;
 
1011
 
 
1012
                                if ( partition_temp .busy && partition_temp .partition_number > device .highest_busy )
 
1013
                                        device .highest_busy = partition_temp .partition_number ;
 
1014
 
 
1015
                                break ;
 
1016
                        
 
1017
                        case PED_PARTITION_EXTENDED:
 
1018
#ifndef USE_LIBPARTED_DMRAID
 
1019
                                //Handle dmraid devices differently because the minor number might not
 
1020
                                //  match the last number of the partition filename as shown by "ls -l /dev/mapper"
 
1021
                                //  This mismatch causes incorrect identification of busy partitions in ped_partition_is_busy(). 
 
1022
                                if ( dmraid .is_dmraid_device( device .get_path() ) )
 
1023
                                {
 
1024
                                        for ( unsigned int k = 5; k < 255; k++ )
 
1025
                                        {
 
1026
                                                //Try device_name + [5 to 255]
 
1027
                                                iter_mp = mount_info .find( device .get_path() + Utils::num_to_str( k ) ) ;
 
1028
                                                if ( iter_mp != mount_info .end() )
 
1029
                                                        partition_is_busy = true ;
 
1030
                                                //Try device_name + p + [5 to 255]
 
1031
                                                iter_mp = mount_info .find( device .get_path() + "p" + Utils::num_to_str( k ) ) ;
 
1032
                                                if ( iter_mp != mount_info .end() )
 
1033
                                                        partition_is_busy = true ;
 
1034
                                        }
 
1035
                                }
 
1036
                                else
 
1037
#endif
 
1038
                                        partition_is_busy = ped_partition_is_busy( lp_partition ) ;
 
1039
 
 
1040
                                partition_temp .Set( device .get_path(),
 
1041
                                                     partition_path, 
 
1042
                                                     lp_partition ->num,
 
1043
                                                     GParted::TYPE_EXTENDED,
 
1044
                                                     GParted::FS_EXTENDED,
 
1045
                                                     lp_partition ->geom .start,
 
1046
                                                     lp_partition ->geom .end,
 
1047
                                                     device .sector_size,
 
1048
                                                     false,
 
1049
                                                     partition_is_busy ) ;
 
1050
 
 
1051
                                partition_temp .add_paths( pp_info .get_alternate_paths( partition_temp .get_path() ) ) ;
 
1052
                                set_flags( partition_temp ) ;
 
1053
 
 
1054
                                EXT_INDEX = device .partitions .size() ;
 
1055
                                break ;
 
1056
 
 
1057
                        default:
 
1058
                                break;
 
1059
                }
 
1060
 
 
1061
                //Avoid reading additional file system information if there is no path
 
1062
                if ( partition_temp .get_path() != "" )
 
1063
                {
 
1064
                        //Retrieve file system label
 
1065
                        //  Use file system specific method first in an effort to ensure multi-byte
 
1066
                        //  character sets are properly displayed.
 
1067
                        read_label( partition_temp ) ;
 
1068
                        if ( partition_temp .label .empty() )
 
1069
                        {
 
1070
                                bool label_found = false ;
 
1071
                                partition_temp .label = fs_info .get_label( partition_temp .get_path(), label_found ) ;
 
1072
                        }
 
1073
 
 
1074
                        //Retrieve file system UUID
 
1075
                        //  Use cached method first in an effort to speed up device scanning.
 
1076
                        partition_temp .uuid = fs_info .get_uuid( partition_temp .get_path() ) ;
 
1077
                        if ( partition_temp .uuid .empty() )
 
1078
                        {
 
1079
                                read_uuid( partition_temp ) ;
 
1080
                        }
 
1081
                }
 
1082
 
 
1083
                partition_temp .messages .insert( partition_temp .messages .end(),
 
1084
                                                  libparted_messages. begin(),
 
1085
                                                  libparted_messages .end() ) ;
 
1086
                
 
1087
                //if there's an end, there's a partition ;)
 
1088
                if ( partition_temp .sector_end > -1 )
 
1089
                {
 
1090
                        if ( ! partition_temp .inside_extended )
 
1091
                                device .partitions .push_back( partition_temp );
 
1092
                        else
 
1093
                                device .partitions[ EXT_INDEX ] .logicals .push_back( partition_temp ) ;
 
1094
                }
 
1095
 
 
1096
                //next partition (if any)
 
1097
                lp_partition = ped_disk_next_partition( lp_disk, lp_partition ) ;
 
1098
        }
 
1099
 
 
1100
        if ( EXT_INDEX > -1 )
 
1101
                insert_unallocated( device .get_path(),
 
1102
                                    device .partitions[ EXT_INDEX ] .logicals,
 
1103
                                    device .partitions[ EXT_INDEX ] .sector_start,
 
1104
                                    device .partitions[ EXT_INDEX ] .sector_end,
 
1105
                                    device .sector_size,
 
1106
                                    true ) ;
 
1107
 
 
1108
        insert_unallocated( device .get_path(), device .partitions, 0, device .length -1, device .sector_size, false ) ; 
 
1109
}
 
1110
 
 
1111
GParted::FILESYSTEM GParted_Core::get_filesystem() 
 
1112
{
 
1113
        char magic1[16] = "";
 
1114
        char magic2[16] = "";
 
1115
 
 
1116
        //Check for LUKS encryption prior to libparted file system detection.
 
1117
        //  Otherwise encrypted file systems such as ext3 will be detected by
 
1118
        //  libparted as 'ext3'.
 
1119
 
 
1120
        //LUKS encryption
 
1121
        char * buf = static_cast<char *>( malloc( lp_device ->sector_size ) ) ;
 
1122
        if ( buf )
 
1123
        {
 
1124
                ped_device_open( lp_device );
 
1125
                ped_geometry_read( & lp_partition ->geom, buf, 0, 1 ) ;
 
1126
                memcpy(magic1, buf+0, 6) ;  //set binary magic data
 
1127
                ped_device_close( lp_device );
 
1128
                free( buf ) ;
 
1129
 
 
1130
                if ( 0 == memcmp( magic1 , "LUKS\xBA\xBE", 6 ) )
 
1131
                {
 
1132
                        temp = _( "Linux Unified Key Setup encryption is not yet supported." ) ;
 
1133
                        temp += "\n" ;
 
1134
                        partition_temp .messages .push_back( temp ) ;
 
1135
                        return GParted::FS_LUKS ;
 
1136
                }
 
1137
        }
 
1138
 
 
1139
        FS_Info fs_info ;
 
1140
        Glib::ustring fs_type = "" ;
 
1141
 
 
1142
        //Standard libparted file system detection
 
1143
        if ( lp_partition && lp_partition ->fs_type )
 
1144
        {
 
1145
                fs_type = lp_partition ->fs_type ->name ;
 
1146
 
 
1147
                //TODO:  Temporary code to detect ext4.
 
1148
                //       Replace when libparted >= 1.9.0 is chosen as minimum required version.
 
1149
                temp = fs_info .get_fs_type( get_partition_path( lp_partition ) ) ;
 
1150
                if ( temp == "ext4" || temp == "ext4dev" )
 
1151
                        fs_type = temp ;
 
1152
        }
 
1153
 
 
1154
        //FS_Info (blkid) file system detection because current libparted (v2.2) does not
 
1155
        //  appear to detect file systems for sector sizes other than 512 bytes.
 
1156
        if ( fs_type .empty() )
 
1157
        {
 
1158
                //TODO: blkid does not return anything for an "extended" partition.  Need to handle this somehow
 
1159
                fs_type = fs_info.get_fs_type( get_partition_path( lp_partition ) ) ;
 
1160
        }
 
1161
 
 
1162
        if ( ! fs_type .empty() )
 
1163
        {
 
1164
                if ( fs_type == "extended" )
 
1165
                        return GParted::FS_EXTENDED ;
 
1166
                else if ( fs_type == "btrfs" )
 
1167
                        return GParted::FS_BTRFS ;
 
1168
                else if ( fs_type == "exfat" )
 
1169
                        return GParted::FS_EXFAT ;
 
1170
                else if ( fs_type == "ext2" )
 
1171
                        return GParted::FS_EXT2 ;
 
1172
                else if ( fs_type == "ext3" )
 
1173
                        return GParted::FS_EXT3 ;
 
1174
                else if ( fs_type == "ext4" ||
 
1175
                          fs_type == "ext4dev" )
 
1176
                        return GParted::FS_EXT4 ;
 
1177
                else if ( fs_type == "linux-swap" ||
 
1178
                          fs_type == "linux-swap(v1)" ||
 
1179
                          fs_type == "linux-swap(new)" ||
 
1180
                          fs_type == "linux-swap(v0)" ||
 
1181
                          fs_type == "linux-swap(old)" ||
 
1182
                          fs_type == "swap" )
 
1183
                        return GParted::FS_LINUX_SWAP ;
 
1184
                else if ( fs_type == "LVM2_member" )
 
1185
                        return GParted::FS_LVM2_PV ;
 
1186
                else if ( fs_type == "fat16" )
 
1187
                        return GParted::FS_FAT16 ;
 
1188
                else if ( fs_type == "fat32" )
 
1189
                        return GParted::FS_FAT32 ;
 
1190
                else if ( fs_type == "nilfs2" )
 
1191
                        return GParted::FS_NILFS2 ;
 
1192
                else if ( fs_type == "ntfs" )
 
1193
                        return GParted::FS_NTFS ;
 
1194
                else if ( fs_type == "reiserfs" )
 
1195
                        return GParted::FS_REISERFS ;
 
1196
                else if ( fs_type == "xfs" )
 
1197
                        return GParted::FS_XFS ;
 
1198
                else if ( fs_type == "jfs" )
 
1199
                        return GParted::FS_JFS ;
 
1200
                else if ( fs_type == "hfs" )
 
1201
                        return GParted::FS_HFS ;
 
1202
                else if ( fs_type == "hfs+" ||
 
1203
                          fs_type == "hfsplus" )
 
1204
                        return GParted::FS_HFSPLUS ;
 
1205
                else if ( fs_type == "ufs" )
 
1206
                        return GParted::FS_UFS ;
 
1207
        }
 
1208
 
 
1209
 
 
1210
 
 
1211
        //other file systems libparted couldn't detect (i've send patches for these file systems to the parted guys)
 
1212
        // - no patches sent to parted for lvm2, or luks
 
1213
 
 
1214
        //reiser4
 
1215
        buf = static_cast<char *>( malloc( lp_device ->sector_size ) ) ;
 
1216
        if ( buf )
 
1217
        {
 
1218
                ped_device_open( lp_device );
 
1219
                ped_geometry_read( & lp_partition ->geom
 
1220
                                 , buf
 
1221
                                 , (65536 / lp_device ->sector_size) 
 
1222
                                 , 1
 
1223
                                 ) ;
 
1224
                memcpy(magic1, buf+0, 7) ; //set binary magic data
 
1225
                ped_device_close( lp_device );
 
1226
                free( buf ) ;
 
1227
 
 
1228
                if ( 0 == memcmp( magic1, "ReIsEr4", 7 ) )
 
1229
                        return GParted::FS_REISER4 ;
 
1230
        }
 
1231
 
 
1232
        //lvm2
 
1233
        //NOTE: lvm2 is not a file system but we do wish to recognize the Physical Volume
 
1234
        buf = static_cast<char *>( malloc( lp_device ->sector_size ) ) ;
 
1235
        if ( buf )
 
1236
        {
 
1237
                ped_device_open( lp_device );
 
1238
                if ( lp_device ->sector_size == 512 )
 
1239
                {
 
1240
                        ped_geometry_read( & lp_partition ->geom, buf, 1, 1 ) ;
 
1241
                        memcpy(magic1, buf+ 0, 8) ; // set binary magic data
 
1242
                        memcpy(magic2, buf+24, 4) ; // set binary magic data
 
1243
                }
 
1244
                else
 
1245
                {
 
1246
                        ped_geometry_read( & lp_partition ->geom, buf, 0, 1 ) ;
 
1247
                        memcpy(magic1, buf+ 0+512, 8) ; // set binary magic data
 
1248
                        memcpy(magic2, buf+24+512, 4) ; // set binary magic data
 
1249
                }
 
1250
                ped_device_close( lp_device );
 
1251
                free( buf ) ;
 
1252
 
 
1253
                if (    0 == memcmp( magic1, "LABELONE", 8 )
 
1254
                     && 0 == memcmp( magic2, "LVM2", 4 ) )
 
1255
                {
 
1256
                        return GParted::FS_LVM2_PV ;
 
1257
                }
 
1258
        }
 
1259
 
 
1260
        //btrfs
 
1261
        const Sector BTRFS_SUPER_INFO_SIZE   = 4096 ;
 
1262
        const Sector BTRFS_SUPER_INFO_OFFSET = (64 * 1024) ;
 
1263
        const char* const BTRFS_SIGNATURE  = "_BHRfS_M" ;
 
1264
 
 
1265
        char    buf_btrfs[BTRFS_SUPER_INFO_SIZE] ;
 
1266
 
 
1267
        ped_device_open( lp_device ) ;
 
1268
        ped_geometry_read( & lp_partition ->geom
 
1269
                         , buf_btrfs
 
1270
                         , (BTRFS_SUPER_INFO_OFFSET / lp_device ->sector_size)
 
1271
                         , (BTRFS_SUPER_INFO_SIZE / lp_device ->sector_size)
 
1272
                         ) ;
 
1273
        memcpy(magic1, buf_btrfs+64, strlen(BTRFS_SIGNATURE) ) ;  //set binary magic data
 
1274
        ped_device_close( lp_device ) ;
 
1275
 
 
1276
        if ( 0 == memcmp( magic1, BTRFS_SIGNATURE, strlen(BTRFS_SIGNATURE) ) )
 
1277
        {
 
1278
                return GParted::FS_BTRFS ;
 
1279
        }
 
1280
 
 
1281
        //no file system found....
 
1282
        temp = _( "Unable to detect file system! Possible reasons are:" ) ;
 
1283
        temp += "\n- "; 
 
1284
        temp += _( "The file system is damaged" ) ;
 
1285
        temp += "\n- " ; 
 
1286
        temp += _( "The file system is unknown to GParted" ) ;
 
1287
        temp += "\n- "; 
 
1288
        temp += _( "There is no file system available (unformatted)" ) ; 
 
1289
        temp += "\n- "; 
 
1290
        /* TO TRANSLATORS: looks like  The device entry /dev/sda5 is missing */
 
1291
        temp += String::ucompose( _( "The device entry %1 is missing" ), get_partition_path( lp_partition ) ) ;
 
1292
        
 
1293
        partition_temp .messages .push_back( temp ) ;
 
1294
        
 
1295
        return GParted::FS_UNKNOWN ;
 
1296
}
 
1297
        
 
1298
void GParted_Core::read_label( Partition & partition )
 
1299
{
 
1300
        if ( partition .type != TYPE_EXTENDED )
 
1301
        {
 
1302
                switch( get_fs( partition .filesystem ) .read_label )
 
1303
                {
 
1304
                        case FS::EXTERNAL:
 
1305
                                if ( set_proper_filesystem( partition .filesystem ) )
 
1306
                                        p_filesystem ->read_label( partition ) ;
 
1307
                                break ;
 
1308
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
 
1309
                        case FS::LIBPARTED:
 
1310
                                break ;
 
1311
#endif
 
1312
 
 
1313
                        default:
 
1314
                                break ;
 
1315
                }
 
1316
        }
 
1317
}
 
1318
 
 
1319
void GParted_Core::read_uuid( Partition & partition )
 
1320
{
 
1321
        if ( partition .type != TYPE_EXTENDED )
 
1322
        {
 
1323
                switch( get_fs( partition .filesystem ) .read_uuid )
 
1324
                {
 
1325
                        case FS::EXTERNAL:
 
1326
                                if ( set_proper_filesystem( partition .filesystem ) )
 
1327
                                        p_filesystem ->read_uuid( partition ) ;
 
1328
                                break ;
 
1329
 
 
1330
                        default:
 
1331
                                break ;
 
1332
                }
 
1333
        }
 
1334
}
 
1335
 
 
1336
void GParted_Core::insert_unallocated( const Glib::ustring & device_path,
 
1337
                                       std::vector<Partition> & partitions,
 
1338
                                       Sector start,
 
1339
                                       Sector end,
 
1340
                                       Byte_Value sector_size,
 
1341
                                       bool inside_extended )
 
1342
{
 
1343
        partition_temp .Reset() ;
 
1344
        partition_temp .Set_Unallocated( device_path, 0, 0, sector_size, inside_extended ) ;
 
1345
        
 
1346
        //if there are no partitions at all..
 
1347
        if ( partitions .empty() )
 
1348
        {
 
1349
                partition_temp .sector_start = start ;
 
1350
                partition_temp .sector_end = end ;
 
1351
                
 
1352
                partitions .push_back( partition_temp );
 
1353
                
 
1354
                return ;
 
1355
        }
 
1356
                
 
1357
        //start <---> first partition start
 
1358
        if ( (partitions .front() .sector_start - start) > (MEBIBYTE / sector_size) )
 
1359
        {
 
1360
                partition_temp .sector_start = start ;
 
1361
                partition_temp .sector_end = partitions .front() .sector_start -1 ;
 
1362
                
 
1363
                partitions .insert( partitions .begin(), partition_temp );
 
1364
        }
 
1365
        
 
1366
        //look for gaps in between
 
1367
        for ( unsigned int t =0 ; t < partitions .size() -1 ; t++ )
 
1368
        {
 
1369
                if (   ( ( partitions[ t + 1 ] .sector_start - partitions[ t ] .sector_end - 1 ) > (MEBIBYTE / sector_size) )
 
1370
                    || (   ( partitions[ t + 1 ] .type != TYPE_LOGICAL )  // Only show exactly 1 MiB if following partition is not logical.
 
1371
                        && ( ( partitions[ t + 1 ] .sector_start - partitions[ t ] .sector_end - 1 ) == (MEBIBYTE / sector_size) )
 
1372
                       )
 
1373
                   )
 
1374
                {
 
1375
                        partition_temp .sector_start = partitions[ t ] .sector_end +1 ;
 
1376
                        partition_temp .sector_end = partitions[ t +1 ] .sector_start -1 ;
 
1377
 
 
1378
                        partitions .insert( partitions .begin() + ++t, partition_temp );
 
1379
                }
 
1380
        }
 
1381
 
 
1382
        //last partition end <---> end
 
1383
        if ( (end - partitions .back() .sector_end) >= (MEBIBYTE / sector_size) )
 
1384
        {
 
1385
                partition_temp .sector_start = partitions .back() .sector_end +1 ;
 
1386
                partition_temp .sector_end = end ;
 
1387
                
 
1388
                partitions .push_back( partition_temp );
 
1389
        }
 
1390
}
 
1391
        
 
1392
void GParted_Core::set_mountpoints( std::vector<Partition> & partitions ) 
 
1393
{
 
1394
#ifndef USE_LIBPARTED_DMRAID
 
1395
        DMRaid dmraid ; //Use cache of dmraid device information
 
1396
#endif
 
1397
        LVM2_PV_Info lvm2_pv_info ;
 
1398
        for ( unsigned int t = 0 ; t < partitions .size() ; t++ )
 
1399
        {
 
1400
                if ( ( partitions[ t ] .type == GParted::TYPE_PRIMARY ||
 
1401
                       partitions[ t ] .type == GParted::TYPE_LOGICAL
 
1402
                     ) &&
 
1403
                     partitions[ t ] .filesystem != GParted::FS_LINUX_SWAP &&
 
1404
                     partitions[ t ] .filesystem != GParted::FS_LVM2_PV    &&
 
1405
                     partitions[ t ] .filesystem != GParted::FS_LUKS
 
1406
                   )
 
1407
                {
 
1408
                        if ( partitions[ t ] .busy )
 
1409
                        {
 
1410
#ifndef USE_LIBPARTED_DMRAID
 
1411
                                //Handle dmraid devices differently because there may be more
 
1412
                                //  than one partition name.
 
1413
                                //  E.g., there might be names with and/or without a 'p' between
 
1414
                                //        the device name and partition number.
 
1415
                                if ( dmraid .is_dmraid_device( partitions[ t ] .device_path ) )
 
1416
                                {
 
1417
                                        //Try device_name + partition_number
 
1418
                                        iter_mp = mount_info .find( partitions[ t ] .device_path + Utils::num_to_str( partitions[ t ] .partition_number ) ) ;
 
1419
                                        if ( iter_mp != mount_info .end() )
 
1420
                                        {
 
1421
                                                partitions[ t ] .add_mountpoints( iter_mp ->second ) ;
 
1422
                                                break ;
 
1423
                                        }
 
1424
                                        //Try device_name + p + partition_number
 
1425
                                        iter_mp = mount_info .find( partitions[ t ] .device_path + "p" + Utils::num_to_str( partitions[ t ] .partition_number ) ) ;
 
1426
                                        if ( iter_mp != mount_info .end() )
 
1427
                                        {
 
1428
                                                partitions[ t ] .add_mountpoints( iter_mp ->second ) ;
 
1429
                                                break ;
 
1430
                                        }
 
1431
                                }
 
1432
                                else
 
1433
                                {
 
1434
#endif
 
1435
                                        //Normal device, not DMRaid device
 
1436
                                        for ( unsigned int i = 0 ; i < partitions[ t ] .get_paths() .size() ; i++ )
 
1437
                                        {
 
1438
                                                iter_mp = mount_info .find( partitions[ t ] .get_paths()[ i ] ) ;
 
1439
                                                if ( iter_mp != mount_info .end() )
 
1440
                                                {
 
1441
                                                        partitions[ t ] .add_mountpoints( iter_mp ->second ) ;
 
1442
                                                        break ;
 
1443
                                                }
 
1444
                                        }
 
1445
#ifndef USE_LIBPARTED_DMRAID
 
1446
                                }
 
1447
#endif
 
1448
 
 
1449
                                if ( partitions[ t ] .get_mountpoints() .empty() )
 
1450
                                        partitions[ t ] .messages .push_back( _("Unable to find mount point") ) ;
 
1451
                        }
 
1452
                        else
 
1453
                        {
 
1454
                                iter_mp = fstab_info .find( partitions[ t ] .get_path() );
 
1455
                                if ( iter_mp != fstab_info .end() )
 
1456
                                        partitions[ t ] .add_mountpoints( iter_mp ->second ) ;
 
1457
                        }
 
1458
                }
 
1459
                else if ( partitions[ t ] .type == GParted::TYPE_EXTENDED )
 
1460
                        set_mountpoints( partitions[ t ] .logicals ) ;
 
1461
                else if ( partitions[ t ] .filesystem == GParted::FS_LVM2_PV )
 
1462
                {
 
1463
                        Glib::ustring vgname = lvm2_pv_info. get_vg_name( partitions[t].get_path() ) ;
 
1464
                        if ( ! vgname .empty() )
 
1465
                                partitions[ t ] .add_mountpoint( vgname ) ;
 
1466
                }
 
1467
        }
 
1468
}
 
1469
        
 
1470
void GParted_Core::set_used_sectors( std::vector<Partition> & partitions ) 
 
1471
{
 
1472
        struct statvfs sfs ; 
 
1473
 
 
1474
        for ( unsigned int t = 0 ; t < partitions .size() ; t++ )
 
1475
        {
 
1476
                if ( partitions[ t ] .filesystem != GParted::FS_LINUX_SWAP &&
 
1477
                     partitions[ t ] .filesystem != GParted::FS_LUKS       &&
 
1478
                     partitions[ t ] .filesystem != GParted::FS_UNKNOWN
 
1479
                   )
 
1480
                {
 
1481
                        if ( partitions[ t ] .type == GParted::TYPE_PRIMARY ||
 
1482
                             partitions[ t ] .type == GParted::TYPE_LOGICAL ) 
 
1483
                        {
 
1484
                                if ( partitions[ t ] .busy && partitions[t] .filesystem != GParted::FS_LVM2_PV )
 
1485
                                {
 
1486
                                        if ( partitions[ t ] .get_mountpoints() .size() > 0  )
 
1487
                                        {
 
1488
                                                if ( statvfs( partitions[ t ] .get_mountpoint() .c_str(), &sfs ) == 0 )
 
1489
                                                        partitions[ t ] .Set_Unused( sfs .f_bfree * (sfs .f_bsize / partitions[ t ] .sector_size) ) ;
 
1490
                                                else
 
1491
                                                        partitions[ t ] .messages .push_back( 
 
1492
                                                                "statvfs (" + 
 
1493
                                                                partitions[ t ] .get_mountpoint() + 
 
1494
                                                                "): " + 
 
1495
                                                                Glib::strerror( errno ) ) ;
 
1496
                                        }
 
1497
                                }
 
1498
                                else
 
1499
                                {
 
1500
                                        switch( get_fs( partitions[ t ] .filesystem ) .read )
 
1501
                                        {
 
1502
                                                case GParted::FS::EXTERNAL      :
 
1503
                                                        if ( set_proper_filesystem( partitions[ t ] .filesystem ) )
 
1504
                                                                p_filesystem ->set_used_sectors( partitions[ t ] ) ;
 
1505
                                                        break ;
 
1506
#ifdef HAVE_LIBPARTED_FS_RESIZE
 
1507
                                                case GParted::FS::LIBPARTED     :
 
1508
                                                        LP_set_used_sectors( partitions[ t ] ) ;
 
1509
                                                        break ;
 
1510
#endif
 
1511
 
 
1512
                                                default:
 
1513
                                                        break ;
 
1514
                                        }
 
1515
                                }
 
1516
 
 
1517
                                if ( partitions[ t ] .sectors_used == -1 )
 
1518
                                {
 
1519
                                        temp = _("Unable to read the contents of this file system!") ;
 
1520
                                        temp += "\n" ;
 
1521
                                        temp += _("Because of this some operations may be unavailable.") ;
 
1522
                                        if ( ! Utils::get_filesystem_software( partitions[ t ] .filesystem ) .empty() )
 
1523
                                        {
 
1524
                                                temp += "\n\n" ;
 
1525
                                                temp += _( "The cause might be a missing software package.") ;
 
1526
                                                temp += "\n" ;
 
1527
                                                /*TO TRANSLATORS: looks like The following list of software packages is required for NTFS file system support:  ntfsprogs. */
 
1528
                                                temp += String::ucompose( _("The following list of software packages is required for %1 file system support:  %2."),
 
1529
                                                                          Utils::get_filesystem_string( partitions[ t ] .filesystem ),
 
1530
                                                                          Utils::get_filesystem_software( partitions[ t ] .filesystem )
 
1531
                                                                        ) ;
 
1532
                                        }
 
1533
                                        partitions[ t ] .messages .push_back( temp ) ;
 
1534
                                }
 
1535
                        }
 
1536
                        else if ( partitions[ t ] .type == GParted::TYPE_EXTENDED )
 
1537
                                set_used_sectors( partitions[ t ] .logicals ) ;
 
1538
                }
 
1539
        }
 
1540
}
 
1541
 
 
1542
#ifdef HAVE_LIBPARTED_FS_RESIZE
 
1543
void GParted_Core::LP_set_used_sectors( Partition & partition )
 
1544
{
 
1545
        PedFileSystem *fs = NULL;
 
1546
        PedConstraint *constraint = NULL;
 
1547
 
 
1548
        if ( lp_disk )
 
1549
        {
 
1550
                lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
 
1551
                
 
1552
                if ( lp_partition )
 
1553
                {
 
1554
                        fs = ped_file_system_open( & lp_partition ->geom );     
 
1555
                                        
 
1556
                        if ( fs )
 
1557
                        {
 
1558
                                constraint = ped_file_system_get_resize_constraint( fs ) ;
 
1559
                                if ( constraint )
 
1560
                                {
 
1561
                                        partition .Set_Unused( partition .get_sector_length() - constraint ->min_size ) ;
 
1562
                                        
 
1563
                                        ped_constraint_destroy( constraint );
 
1564
                                }
 
1565
                                                                                                
 
1566
                                ped_file_system_close( fs ) ;
 
1567
                        }
 
1568
                }
 
1569
        }
 
1570
}
 
1571
#endif
 
1572
 
 
1573
void GParted_Core::set_flags( Partition & partition )
 
1574
{
 
1575
        for ( unsigned int t = 0 ; t < flags .size() ; t++ )
 
1576
                if ( ped_partition_is_flag_available( lp_partition, flags[ t ] ) &&
 
1577
                     ped_partition_get_flag( lp_partition, flags[ t ] ) )
 
1578
                        partition .flags .push_back( ped_partition_flag_get_name( flags[ t ] ) ) ;
 
1579
}
 
1580
 
 
1581
bool GParted_Core::create( const Device & device, Partition & new_partition, OperationDetail & operationdetail ) 
 
1582
{
 
1583
        if ( new_partition .type == GParted::TYPE_EXTENDED )   
 
1584
        {
 
1585
                return create_partition( new_partition, operationdetail ) ;
 
1586
        }
 
1587
        else if ( create_partition( new_partition, operationdetail, (get_fs( new_partition .filesystem ) .MIN / new_partition .sector_size) ) )
 
1588
        {
 
1589
                if ( new_partition .filesystem == GParted::FS_UNFORMATTED )
 
1590
                        return true ;
 
1591
                else
 
1592
                        return set_partition_type( new_partition, operationdetail ) &&
 
1593
                               create_filesystem( new_partition, operationdetail ) ;
 
1594
        }
 
1595
        
 
1596
        return false ;
 
1597
}
 
1598
 
 
1599
bool GParted_Core::create_partition( Partition & new_partition, OperationDetail & operationdetail, Sector min_size )
 
1600
{
 
1601
        operationdetail .add_child( OperationDetail( _("create empty partition") ) ) ;
 
1602
        
 
1603
        new_partition .partition_number = 0 ;
 
1604
                
 
1605
        if ( open_device_and_disk( new_partition .device_path ) )
 
1606
        {
 
1607
                PedPartitionType type;
 
1608
                lp_partition = NULL ;
 
1609
                PedConstraint *constraint = NULL ;
 
1610
                PedFileSystemType* fs_type = NULL ;
 
1611
                
 
1612
                //create new partition
 
1613
                switch ( new_partition .type )
 
1614
                {
 
1615
                        case GParted::TYPE_PRIMARY:
 
1616
                                type = PED_PARTITION_NORMAL ;
 
1617
                                break ;
 
1618
                        case GParted::TYPE_LOGICAL:
 
1619
                                type = PED_PARTITION_LOGICAL ;
 
1620
                                break ;
 
1621
                        case GParted::TYPE_EXTENDED:
 
1622
                                type = PED_PARTITION_EXTENDED ;
 
1623
                                break ;
 
1624
                                
 
1625
                        default :
 
1626
                                type = PED_PARTITION_FREESPACE;
 
1627
                }
 
1628
 
 
1629
                if ( new_partition .type != GParted::TYPE_EXTENDED )
 
1630
                        fs_type = ped_file_system_type_get( "ext2" ) ;
 
1631
 
 
1632
                lp_partition = ped_partition_new( lp_disk,
 
1633
                                                  type,
 
1634
                                                  fs_type,
 
1635
                                                  new_partition .sector_start,
 
1636
                                                  new_partition .sector_end ) ;
 
1637
        
 
1638
                if ( lp_partition )
 
1639
                {
 
1640
                        if (   new_partition .alignment == ALIGN_STRICT
 
1641
                            || new_partition .alignment == ALIGN_MEBIBYTE
 
1642
                           )
 
1643
                        {
 
1644
                                PedGeometry *geom = ped_geometry_new( lp_device,
 
1645
                                                                      new_partition .sector_start,
 
1646
                                                                      new_partition .get_sector_length() ) ;
 
1647
 
 
1648
                                if ( geom )
 
1649
                                        constraint = ped_constraint_exact( geom ) ;
 
1650
                        }
 
1651
                        else
 
1652
                                constraint = ped_constraint_any( lp_device );
 
1653
                        
 
1654
                        if ( constraint )
 
1655
                        {
 
1656
                                if (   min_size > 0
 
1657
                                    && new_partition .filesystem != FS_XFS // Permit copying to smaller xfs partition
 
1658
                                   )
 
1659
                                        constraint ->min_size = min_size ;
 
1660
                
 
1661
                                if ( ped_disk_add_partition( lp_disk, lp_partition, constraint ) && commit() )
 
1662
                                {
 
1663
                                        Glib::ustring partition_path = get_partition_path( lp_partition ) ;
 
1664
                                        new_partition .add_path( partition_path, true ) ;
 
1665
 
 
1666
                                        new_partition .partition_number = lp_partition ->num ;
 
1667
                                        new_partition .sector_start = lp_partition ->geom .start ;
 
1668
                                        new_partition .sector_end = lp_partition ->geom .end ;
 
1669
                                        
 
1670
                                        operationdetail .get_last_child() .add_child( OperationDetail( 
 
1671
                                                String::ucompose( _("path: %1"), new_partition .get_path() ) + "\n" +
 
1672
                                                String::ucompose( _("start: %1"), new_partition .sector_start ) + "\n" +
 
1673
                                                String::ucompose( _("end: %1"), new_partition .sector_end ) + "\n" +
 
1674
                                                String::ucompose( _("size: %1 (%2)"),
 
1675
                                                                new_partition .get_sector_length(),
 
1676
                                                                Utils::format_size( new_partition .get_sector_length(), new_partition .sector_size ) ),
 
1677
                                                STATUS_NONE,
 
1678
                                                FONT_ITALIC ) ) ;
 
1679
                                }
 
1680
                        
 
1681
                                ped_constraint_destroy( constraint );
 
1682
                        }
 
1683
                }
 
1684
                                
 
1685
                close_device_and_disk() ;
 
1686
        }
 
1687
 
 
1688
        bool succes = new_partition .partition_number > 0
 
1689
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
 
1690
                      && erase_filesystem_signatures( new_partition )
 
1691
#endif
 
1692
        ;
 
1693
 
 
1694
#ifndef USE_LIBPARTED_DMRAID
 
1695
        //create dev map entries if dmraid
 
1696
        DMRaid dmraid ;
 
1697
        if ( succes && dmraid .is_dmraid_device( new_partition .device_path ) )
 
1698
                succes = dmraid .create_dev_map_entries( new_partition, operationdetail .get_last_child() ) ;
 
1699
#endif
 
1700
 
 
1701
        operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
1702
 
 
1703
        return succes ;
 
1704
}
 
1705
        
 
1706
bool GParted_Core::create_filesystem( const Partition & partition, OperationDetail & operationdetail ) 
 
1707
{
 
1708
        /*TO TRANSLATORS: looks like create new ext3 file system */ 
 
1709
        operationdetail .add_child( OperationDetail( String::ucompose(
 
1710
                                                        _("create new %1 file system"),
 
1711
                                                        Utils::get_filesystem_string( partition .filesystem ) ) ) ) ;
 
1712
        
 
1713
        bool succes = false ;
 
1714
        switch ( get_fs( partition .filesystem ) .create )
 
1715
        {
 
1716
                case GParted::FS::NONE:
 
1717
                        break ;
 
1718
                case GParted::FS::GPARTED:
 
1719
                        break ;
 
1720
#ifndef HAVE_LIBPARTED_3_0_PLUS
 
1721
                case GParted::FS::LIBPARTED:
 
1722
                        break ;
 
1723
#endif
 
1724
                case GParted::FS::EXTERNAL:
 
1725
                        succes = set_proper_filesystem( partition .filesystem ) &&
 
1726
                                 p_filesystem ->create( partition, operationdetail .get_last_child() ) ;
 
1727
 
 
1728
                        break ;
 
1729
 
 
1730
                default:
 
1731
                        break ;
 
1732
        }
 
1733
 
 
1734
        operationdetail .get_last_child() .set_status(  succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
1735
        return succes ;
 
1736
}
 
1737
 
 
1738
bool GParted_Core::format( const Partition & partition, OperationDetail & operationdetail )
 
1739
{
 
1740
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
 
1741
        //remove all file system signatures...
 
1742
        erase_filesystem_signatures( partition ) ;
 
1743
#endif
 
1744
 
 
1745
        return set_partition_type( partition, operationdetail ) && create_filesystem( partition, operationdetail ) ;
 
1746
}
 
1747
 
 
1748
bool GParted_Core::Delete( const Partition & partition, OperationDetail & operationdetail ) 
 
1749
{
 
1750
        operationdetail .add_child( OperationDetail( _("delete partition") ) ) ;
 
1751
 
 
1752
        bool succes = false ;
 
1753
        if ( open_device_and_disk( partition .device_path ) )
 
1754
        {
 
1755
                if ( partition .type == TYPE_EXTENDED )
 
1756
                        lp_partition = ped_disk_extended_partition( lp_disk ) ;
 
1757
                else
 
1758
                        lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
 
1759
                
 
1760
                succes = ped_disk_delete_partition( lp_disk, lp_partition ) && commit() ;
 
1761
        
 
1762
                close_device_and_disk() ;
 
1763
        }
 
1764
 
 
1765
#ifndef USE_LIBPARTED_DMRAID
 
1766
        //delete partition dev mapper entry, and delete and recreate all other affected dev mapper entries if dmraid
 
1767
        DMRaid dmraid ;
 
1768
        if ( succes && dmraid .is_dmraid_device( partition .device_path ) )
 
1769
        {
 
1770
                //Open disk handle before and close after to prevent application crash.
 
1771
                if ( open_device_and_disk( partition .device_path ) )
 
1772
                {
 
1773
                        if ( ! dmraid .delete_affected_dev_map_entries( partition, operationdetail .get_last_child() ) )
 
1774
                                succes = false ;        //comand failed
 
1775
 
 
1776
                        if ( ! dmraid .create_dev_map_entries( partition, operationdetail .get_last_child() ) )
 
1777
                                succes = false ;        //command failed
 
1778
 
 
1779
                        close_device_and_disk() ;
 
1780
                }
 
1781
        }
 
1782
#endif
 
1783
 
 
1784
        operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
1785
        return succes ;
 
1786
}
 
1787
 
 
1788
bool GParted_Core::label_partition( const Partition & partition, OperationDetail & operationdetail )    
 
1789
{
 
1790
        if( partition .label .empty() ) {
 
1791
                operationdetail .add_child( OperationDetail( String::ucompose(
 
1792
                                                                                                                _("Clear partition label on %1"),
 
1793
                                                                                                                partition .get_path()
 
1794
                                                                                                         ) ) ) ;
 
1795
        } else {
 
1796
                operationdetail .add_child( OperationDetail( String::ucompose(
 
1797
                                                                                                                _("Set partition label to \"%1\" on %2"),
 
1798
                                                                                                                partition .label, partition .get_path()
 
1799
                                                                                                         ) ) ) ;
 
1800
        }
 
1801
 
 
1802
        bool succes = false ;
 
1803
        if ( partition .type != TYPE_EXTENDED )
 
1804
        {
 
1805
                switch( get_fs( partition .filesystem ) .write_label )
 
1806
                {
 
1807
                        case FS::EXTERNAL:
 
1808
                                succes = set_proper_filesystem( partition .filesystem ) &&
 
1809
                                         p_filesystem ->write_label( partition, operationdetail .get_last_child() ) ;
 
1810
                                break ;
 
1811
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
 
1812
                        case FS::LIBPARTED:
 
1813
                                break ;
 
1814
#endif
 
1815
 
 
1816
                        default:
 
1817
                                break ;
 
1818
                }
 
1819
        }
 
1820
 
 
1821
        operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
1822
 
 
1823
        return succes ; 
 
1824
}
 
1825
 
 
1826
bool GParted_Core::change_uuid( const Partition & partition, OperationDetail & operationdetail )
 
1827
{
 
1828
        if ( partition .uuid == UUID_RANDOM_NTFS_HALF ) {
 
1829
                operationdetail .add_child( OperationDetail( String::ucompose(
 
1830
                                                                                _("Set half of the UUID on %1 to a new, random value"),
 
1831
                                                                                 partition .get_path()
 
1832
                                                                         ) ) ) ;
 
1833
        } else {
 
1834
                operationdetail .add_child( OperationDetail( String::ucompose(
 
1835
                                                                                _("Set UUID on %1 to a new, random value"),
 
1836
                                                                                 partition .get_path()
 
1837
                                                                         ) ) ) ;
 
1838
        }
 
1839
 
 
1840
        bool succes = false ;
 
1841
        if ( partition .type != TYPE_EXTENDED )
 
1842
        {
 
1843
                switch( get_fs( partition .filesystem ) .write_uuid )
 
1844
                {
 
1845
                        case FS::EXTERNAL:
 
1846
                                succes = set_proper_filesystem( partition .filesystem ) &&
 
1847
                                         p_filesystem ->write_uuid( partition, operationdetail .get_last_child() ) ;
 
1848
                                break ;
 
1849
 
 
1850
                        default:
 
1851
                                break;
 
1852
                }
 
1853
        }
 
1854
 
 
1855
        operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
1856
 
 
1857
        return succes ;
 
1858
}
 
1859
 
 
1860
bool GParted_Core::resize_move( const Device & device,
 
1861
                                const Partition & partition_old,
 
1862
                                Partition & partition_new,
 
1863
                                OperationDetail & operationdetail ) 
 
1864
{
 
1865
        if (   (partition_new .alignment == ALIGN_STRICT)
 
1866
            || (partition_new .alignment == ALIGN_MEBIBYTE)
 
1867
            || partition_new .strict_start
 
1868
            || calculate_exact_geom( partition_old, partition_new, operationdetail )
 
1869
           )
 
1870
        {
 
1871
                if ( partition_old .type == TYPE_EXTENDED )
 
1872
                        return resize_move_partition( partition_old, partition_new, operationdetail ) ;
 
1873
 
 
1874
                if ( partition_new .sector_start == partition_old .sector_start )
 
1875
                        return resize( partition_old, partition_new, operationdetail ) ;
 
1876
 
 
1877
                if ( partition_new .get_sector_length() == partition_old .get_sector_length() )
 
1878
                        return move( device, partition_old, partition_new, operationdetail ) ;
 
1879
 
 
1880
                Partition temp ;
 
1881
                if ( partition_new .get_sector_length() > partition_old .get_sector_length() )
 
1882
                {
 
1883
                        //first move, then grow. Since old.length < new.length and new.start is valid, temp is valid.
 
1884
                        temp = partition_new ;
 
1885
                        temp .sector_end = temp .sector_start + partition_old .get_sector_length() -1 ;
 
1886
                }
 
1887
 
 
1888
                if ( partition_new .get_sector_length() < partition_old .get_sector_length() )
 
1889
                {
 
1890
                        //first shrink, then move. Since new.length < old.length and old.start is valid, temp is valid.
 
1891
                        temp = partition_old ;
 
1892
                        temp .sector_end = partition_old .sector_start + partition_new .get_sector_length() -1 ;
 
1893
                }
 
1894
 
 
1895
                PartitionAlignment previous_alignment = temp .alignment ;
 
1896
                temp .alignment = ALIGN_STRICT ;
 
1897
                bool succes = resize_move( device, partition_old, temp, operationdetail ) ;
 
1898
                temp .alignment = previous_alignment ;
 
1899
 
 
1900
                return succes && resize_move( device, temp, partition_new, operationdetail ) ;
 
1901
        }
 
1902
 
 
1903
        return false ;
 
1904
}
 
1905
 
 
1906
bool GParted_Core::move( const Device & device,
 
1907
                         const Partition & partition_old,
 
1908
                         const Partition & partition_new,
 
1909
                         OperationDetail & operationdetail ) 
 
1910
{
 
1911
        if ( partition_old .get_sector_length() != partition_new .get_sector_length() )
 
1912
        {       
 
1913
                operationdetail .add_child( OperationDetail(
 
1914
                                /* TO TRANSLATORS:  moving requires old and new length to be the same
 
1915
                                 * means that the length in bytes of the old partition and new partition
 
1916
                                 * must be the same.  If the sector sizes of the old partition and the
 
1917
                                 * new partition are the same, then the length in sectors must be the same.
 
1918
                                 */
 
1919
                                _("moving requires old and new length to be the same"), STATUS_ERROR, FONT_ITALIC ) ) ;
 
1920
 
 
1921
                return false ;
 
1922
        }
 
1923
 
 
1924
        bool succes = false ;
 
1925
        if ( check_repair_filesystem( partition_old, operationdetail ) )
 
1926
        {
 
1927
                //NOTE: Logical partitions are preceded by meta data.  To prevent this
 
1928
                //      meta data from being overwritten we first expand the partition to
 
1929
                //      encompass all of the space involved in the move.  In this way we
 
1930
                //      prevent overwriting the meta data for this partition when we move
 
1931
                //      this partition to the left.  We also prevent overwriting the meta
 
1932
                //      data of a following partition when we move this partition to the
 
1933
                //      right.
 
1934
                Partition partition_all_space = partition_old ;
 
1935
                partition_all_space .alignment = ALIGN_STRICT ;
 
1936
                if ( partition_new .sector_start < partition_all_space. sector_start )
 
1937
                        partition_all_space .sector_start = partition_new. sector_start ;
 
1938
                if ( partition_new .sector_end > partition_all_space.sector_end )
 
1939
                        partition_all_space .sector_end = partition_new. sector_end ;
 
1940
 
 
1941
                //Make old partition all encompassing and if move file system fails
 
1942
                //  then return partition table to original state
 
1943
                if ( resize_move_partition( partition_old, partition_all_space, operationdetail ) )
 
1944
                {
 
1945
                        //Note move of file system is from old values to new values, not from
 
1946
                        //  the all encompassing values.
 
1947
                        if ( ! move_filesystem( partition_old, partition_new, operationdetail ) )
 
1948
                        {
 
1949
                                operationdetail .add_child( OperationDetail( _("rollback last change to the partition table") ) ) ;
 
1950
 
 
1951
                                Partition partition_restore = partition_old ;
 
1952
                                partition_restore .alignment = ALIGN_STRICT ;  //Ensure that old partition boundaries are not modified
 
1953
                                if ( resize_move_partition( partition_all_space, partition_restore, operationdetail .get_last_child() ) )
 
1954
                                        operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
 
1955
                                else
 
1956
                                        operationdetail .get_last_child() .set_status( STATUS_ERROR ) ;
 
1957
                        }
 
1958
                        else
 
1959
                                succes = true ;
 
1960
                }
 
1961
 
 
1962
                //Make new partition from all encompassing partition
 
1963
                succes =  succes && resize_move_partition( partition_all_space, partition_new, operationdetail ) ;
 
1964
 
 
1965
                succes = (    succes
 
1966
                          && update_bootsector( partition_new, operationdetail )
 
1967
                          && (   //Do not maximize file system if FS not linux-swap and new size <= old
 
1968
                                 (   partition_new .filesystem != FS_LINUX_SWAP  //linux-swap is recreated, not moved
 
1969
                                  && partition_new .get_sector_length() <= partition_old .get_sector_length()
 
1970
                                 )
 
1971
                              || (   check_repair_filesystem( partition_new, operationdetail )
 
1972
                                  && maximize_filesystem( partition_new, operationdetail )
 
1973
                                 )
 
1974
                             )
 
1975
                         );
 
1976
 
 
1977
        }
 
1978
 
 
1979
        return succes ;
 
1980
}
 
1981
 
 
1982
bool GParted_Core::move_filesystem( const Partition & partition_old,
 
1983
                                    const Partition & partition_new,
 
1984
                                    OperationDetail & operationdetail ) 
 
1985
{
 
1986
        if ( partition_new .sector_start < partition_old .sector_start )
 
1987
                operationdetail .add_child( OperationDetail( _("move file system to the left") ) ) ;
 
1988
        else if ( partition_new .sector_start > partition_old .sector_start )
 
1989
                operationdetail .add_child( OperationDetail( _("move file system to the right") ) ) ;
 
1990
        else
 
1991
        {
 
1992
                operationdetail .add_child( OperationDetail( _("move file system") ) ) ;
 
1993
                operationdetail .get_last_child() .add_child( 
 
1994
                        OperationDetail( _("new and old file system have the same position.  Hence skipping this operation"),
 
1995
                                         STATUS_NONE,
 
1996
                                         FONT_ITALIC ) ) ;
 
1997
 
 
1998
                operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
 
1999
                return true ;
 
2000
        }
 
2001
 
 
2002
        bool succes = false ;
 
2003
        switch ( get_fs( partition_old .filesystem ) .move )
 
2004
        {
 
2005
                case GParted::FS::NONE:
 
2006
                        break ;
 
2007
                case GParted::FS::GPARTED:
 
2008
                        succes = false ;
 
2009
                        if ( partition_new .test_overlap( partition_old ) )
 
2010
                        {
 
2011
                                if ( copy_filesystem_simulation( partition_old, partition_new, operationdetail .get_last_child() ) )
 
2012
                                {
 
2013
                                        operationdetail .get_last_child() .add_child( OperationDetail( _("perform real move") ) ) ;
 
2014
                                        
 
2015
                                        Sector total_done ;
 
2016
                                        succes = copy_filesystem( partition_old,
 
2017
                                                                  partition_new,
 
2018
                                                                  operationdetail .get_last_child() .get_last_child(),
 
2019
                                                                  total_done ) ;
 
2020
                                        
 
2021
                                        operationdetail .get_last_child() .get_last_child() 
 
2022
                                                .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
2023
                                        if ( ! succes )
 
2024
                                        {
 
2025
                                                rollback_transaction( partition_old,
 
2026
                                                                      partition_new,
 
2027
                                                                      operationdetail .get_last_child(),
 
2028
                                                                      total_done ) ;
 
2029
 
 
2030
                                                check_repair_filesystem( partition_old, operationdetail ) ;
 
2031
                                        }
 
2032
                                }
 
2033
                        }
 
2034
                        else
 
2035
                                succes = copy_filesystem( partition_old, partition_new, operationdetail .get_last_child() ) ;
 
2036
 
 
2037
                        break ;
 
2038
#ifdef HAVE_LIBPARTED_FS_RESIZE
 
2039
                case GParted::FS::LIBPARTED:
 
2040
                        succes = resize_move_filesystem_using_libparted( partition_old,
 
2041
                                                                         partition_new,
 
2042
                                                                         operationdetail .get_last_child() ) ;
 
2043
                        break ;
 
2044
#endif
 
2045
                case GParted::FS::EXTERNAL:
 
2046
                        succes = set_proper_filesystem( partition_new .filesystem ) &&
 
2047
                                 p_filesystem ->move( partition_old
 
2048
                                                    , partition_new
 
2049
                                                    , operationdetail .get_last_child()
 
2050
                                                    ) ;
 
2051
                        break ;
 
2052
 
 
2053
                default:
 
2054
                        break ;
 
2055
        }
 
2056
 
 
2057
        operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
2058
        return succes ;
 
2059
}
 
2060
 
 
2061
#ifdef HAVE_LIBPARTED_FS_RESIZE
 
2062
bool GParted_Core::resize_move_filesystem_using_libparted( const Partition & partition_old,
 
2063
                                                           const Partition & partition_new,
 
2064
                                                           OperationDetail & operationdetail ) 
 
2065
{
 
2066
        operationdetail .add_child( OperationDetail( _("using libparted"), STATUS_NONE ) ) ;
 
2067
 
 
2068
        bool return_value = false ;
 
2069
        if ( open_device_and_disk( partition_old .device_path ) )
 
2070
        {
 
2071
                PedFileSystem * fs = NULL ;
 
2072
                PedGeometry * lp_geom = NULL ;  
 
2073
                
 
2074
                lp_geom = ped_geometry_new( lp_device,
 
2075
                                            partition_old .sector_start,
 
2076
                                            partition_old .get_sector_length() ) ;
 
2077
                if ( lp_geom )
 
2078
                {
 
2079
                        fs = ped_file_system_open( lp_geom );
 
2080
                        if ( fs )
 
2081
                        {
 
2082
                                lp_geom = NULL ;
 
2083
                                lp_geom = ped_geometry_new( lp_device,
 
2084
                                                            partition_new .sector_start,
 
2085
                                                            partition_new .get_sector_length() ) ;
 
2086
                                if ( lp_geom )
 
2087
                                        return_value = ped_file_system_resize( fs, lp_geom, NULL ) && commit() ;
 
2088
 
 
2089
                                ped_file_system_close( fs );
 
2090
                        }
 
2091
                }
 
2092
 
 
2093
                close_device_and_disk() ;
 
2094
        }
 
2095
 
 
2096
        return return_value ;
 
2097
}
 
2098
#endif
 
2099
 
 
2100
bool GParted_Core::resize( const Partition & partition_old, 
 
2101
                           const Partition & partition_new,
 
2102
                           OperationDetail & operationdetail )
 
2103
{
 
2104
        if ( partition_old .sector_start != partition_new .sector_start )
 
2105
        {       
 
2106
                operationdetail .add_child( OperationDetail( 
 
2107
                        _("resizing requires old and new start to be the same"), STATUS_ERROR, FONT_ITALIC ) ) ;
 
2108
 
 
2109
                return false ;
 
2110
        }
 
2111
 
 
2112
        bool succes = false ;
 
2113
        if ( check_repair_filesystem( partition_new, operationdetail ) )
 
2114
        {
 
2115
                succes = true ;
 
2116
 
 
2117
                if ( succes && partition_new .get_sector_length() < partition_old .get_sector_length() )
 
2118
                        succes = resize_filesystem( partition_old, partition_new, operationdetail ) ;
 
2119
 
 
2120
                if ( succes )
 
2121
                        succes = resize_move_partition( partition_old, partition_new, operationdetail ) ;
 
2122
 
 
2123
                //expand file system to fit exactly in partition
 
2124
                if ( ! (   //Do not maximize file system if FS not linux-swap and new size <= old
 
2125
                           (   partition_new .filesystem != FS_LINUX_SWAP  //linux-swap is recreated, not resized
 
2126
                            && partition_new .get_sector_length() <= partition_old .get_sector_length()
 
2127
                           )
 
2128
                        || (   check_repair_filesystem( partition_new, operationdetail )
 
2129
                            && maximize_filesystem( partition_new, operationdetail )
 
2130
                           )
 
2131
                       )
 
2132
                   )
 
2133
                        succes = false ;
 
2134
                        
 
2135
                return succes ;
 
2136
        }
 
2137
                
 
2138
        return false ;
 
2139
}
 
2140
 
 
2141
bool GParted_Core::resize_move_partition( const Partition & partition_old,
 
2142
                                          const Partition & partition_new,
 
2143
                                          OperationDetail & operationdetail )
 
2144
{
 
2145
        //i'm not too happy with this, but i think it is the correct way from a i18n POV
 
2146
        enum Action
 
2147
        {
 
2148
                NONE                    = 0,
 
2149
                MOVE_RIGHT              = 1,
 
2150
                MOVE_LEFT               = 2,
 
2151
                GROW                    = 3,
 
2152
                SHRINK                  = 4,
 
2153
                MOVE_RIGHT_GROW         = 5,
 
2154
                MOVE_RIGHT_SHRINK       = 6,
 
2155
                MOVE_LEFT_GROW          = 7,
 
2156
                MOVE_LEFT_SHRINK        = 8
 
2157
        } ;
 
2158
        Action action = NONE ;
 
2159
 
 
2160
        if ( partition_new .get_sector_length() > partition_old .get_sector_length() )
 
2161
                action = GROW ;
 
2162
        else if ( partition_new .get_sector_length() < partition_old .get_sector_length() )
 
2163
                action = SHRINK ;
 
2164
 
 
2165
        if ( partition_new .sector_start > partition_old .sector_start &&
 
2166
             partition_new .sector_end > partition_old .sector_end )
 
2167
                action = action == GROW ? MOVE_RIGHT_GROW : action == SHRINK ? MOVE_RIGHT_SHRINK : MOVE_RIGHT ;
 
2168
        else if ( partition_new .sector_start < partition_old .sector_start &&
 
2169
             partition_new .sector_end < partition_old .sector_end )
 
2170
                action = action == GROW ? MOVE_LEFT_GROW : action == SHRINK ? MOVE_LEFT_SHRINK : MOVE_LEFT ;
 
2171
 
 
2172
        Glib::ustring description ;     
 
2173
        switch ( action )
 
2174
        {
 
2175
                case NONE               :
 
2176
                        description = _("resize/move partition") ;
 
2177
                        break ;
 
2178
                case MOVE_RIGHT         :
 
2179
                        description = _("move partition to the right") ;
 
2180
                        break ;
 
2181
                case MOVE_LEFT          :
 
2182
                        description = _("move partition to the left") ;
 
2183
                        break ;
 
2184
                case GROW               :
 
2185
                        description = _("grow partition from %1 to %2") ;
 
2186
                        break ;
 
2187
                case SHRINK             :
 
2188
                        description = _("shrink partition from %1 to %2") ;
 
2189
                        break ;
 
2190
                case MOVE_RIGHT_GROW    :
 
2191
                        description = _("move partition to the right and grow it from %1 to %2") ;
 
2192
                        break ;
 
2193
                case MOVE_RIGHT_SHRINK  :
 
2194
                        description = _("move partition to the right and shrink it from %1 to %2") ;
 
2195
                        break ;
 
2196
                case MOVE_LEFT_GROW     :
 
2197
                        description = _("move partition to the left and grow it from %1 to %2") ;
 
2198
                        break ;
 
2199
                case MOVE_LEFT_SHRINK   :
 
2200
                        description = _("move partition to the left and shrink it from %1 to %2") ;
 
2201
                        break ;
 
2202
        }
 
2203
 
 
2204
        if ( ! description .empty() && action != NONE && action != MOVE_LEFT && action != MOVE_RIGHT )
 
2205
                description = String::ucompose( description,
 
2206
                                                Utils::format_size( partition_old .get_sector_length(), partition_old .sector_size ),
 
2207
                                                Utils::format_size( partition_new .get_sector_length(), partition_new .sector_size ) ) ;
 
2208
 
 
2209
        operationdetail .add_child( OperationDetail( description ) ) ;
 
2210
 
 
2211
        
 
2212
        if ( action == NONE )
 
2213
        {
 
2214
                operationdetail .get_last_child() .add_child( 
 
2215
                        OperationDetail( _("new and old partition have the same size and position.  Hence skipping this operation"),
 
2216
                                          STATUS_NONE,
 
2217
                                          FONT_ITALIC ) ) ;
 
2218
 
 
2219
                operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
 
2220
                return true ;
 
2221
        }
 
2222
 
 
2223
        operationdetail .get_last_child() .add_child( 
 
2224
                OperationDetail(
 
2225
                        String::ucompose( _("old start: %1"), partition_old .sector_start ) + "\n" +
 
2226
                        String::ucompose( _("old end: %1"), partition_old .sector_end ) + "\n" +
 
2227
                        String::ucompose( _("old size: %1 (%2)"),
 
2228
                                        partition_old .get_sector_length(),
 
2229
                                        Utils::format_size( partition_old .get_sector_length(), partition_old .sector_size ) ),
 
2230
                STATUS_NONE, 
 
2231
                FONT_ITALIC ) ) ;
 
2232
        
 
2233
        //finally the actual resize/move
 
2234
        bool return_value = false ;
 
2235
        
 
2236
        PedConstraint *constraint = NULL ;
 
2237
        lp_partition = NULL ;
 
2238
 
 
2239
        //sometimes the lp_partition ->geom .start,end and length values display random numbers
 
2240
        //after going out of the 'if ( lp_partition)' scope. That's why we use some variables here.
 
2241
        Sector new_start = -1, new_end = -1 ;
 
2242
                
 
2243
        if ( open_device_and_disk( partition_old .device_path ) )
 
2244
        {
 
2245
                if ( partition_old .type == GParted::TYPE_EXTENDED )
 
2246
                        lp_partition = ped_disk_extended_partition( lp_disk ) ;
 
2247
                else            
 
2248
                        lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition_old .get_sector() ) ;
 
2249
                
 
2250
                if ( lp_partition )
 
2251
                {
 
2252
                        if (   (partition_new .alignment == ALIGN_STRICT)
 
2253
                            || (partition_new .alignment == ALIGN_MEBIBYTE)
 
2254
                            || partition_new .strict_start
 
2255
                           ) {
 
2256
                                PedGeometry *geom = ped_geometry_new( lp_device,
 
2257
                                                                          partition_new .sector_start,
 
2258
                                                                          partition_new .get_sector_length() ) ;
 
2259
                                constraint = ped_constraint_exact( geom ) ;
 
2260
                        }
 
2261
                        else
 
2262
                                constraint = ped_constraint_any( lp_device ) ;
 
2263
 
 
2264
                        if ( constraint )
 
2265
                        {
 
2266
                                if ( ped_disk_set_partition_geom( lp_disk,
 
2267
                                                                  lp_partition,
 
2268
                                                                  constraint,
 
2269
                                                                  partition_new .sector_start,
 
2270
                                                                  partition_new .sector_end ) )
 
2271
                                {
 
2272
                                        new_start = lp_partition ->geom .start ;
 
2273
                                        new_end = lp_partition ->geom .end ;
 
2274
 
 
2275
                                        return_value = commit() ;
 
2276
                                }
 
2277
                                                                        
 
2278
                                ped_constraint_destroy( constraint );
 
2279
                        }
 
2280
                }
 
2281
                
 
2282
                close_device_and_disk() ;
 
2283
        }
 
2284
        
 
2285
        if ( return_value )
 
2286
        {
 
2287
                //Change to partition succeeded
 
2288
                operationdetail .get_last_child() .add_child( 
 
2289
                        OperationDetail(
 
2290
                                String::ucompose( _("new start: %1"), new_start ) + "\n" +
 
2291
                                String::ucompose( _("new end: %1"), new_end ) + "\n" +
 
2292
                                String::ucompose( _("new size: %1 (%2)"),
 
2293
                                                new_end - new_start + 1,
 
2294
                                                Utils::format_size( new_end - new_start + 1, partition_new .sector_size ) ),
 
2295
                        STATUS_NONE, 
 
2296
                        FONT_ITALIC ) ) ;
 
2297
 
 
2298
#ifndef USE_LIBPARTED_DMRAID
 
2299
                //update dev mapper entry if partition is dmraid.
 
2300
                DMRaid dmraid ;
 
2301
                if ( return_value && dmraid .is_dmraid_device( partition_new .device_path ) )
 
2302
                {
 
2303
                        //Open disk handle before and close after to prevent application crash.
 
2304
                        if ( open_device_and_disk( partition_new .device_path ) )
 
2305
                        {
 
2306
                                return_value = dmraid .update_dev_map_entry( partition_new, operationdetail .get_last_child() ) ;
 
2307
                                close_device_and_disk() ;
 
2308
                        }
 
2309
                }
 
2310
#endif
 
2311
        }
 
2312
        else
 
2313
        {
 
2314
                //Change to partition failed
 
2315
                operationdetail .get_last_child() .add_child(
 
2316
                        OperationDetail(
 
2317
                                String::ucompose( _("requested start: %1"), partition_new .sector_start ) + "\n" +
 
2318
                                String::ucompose( _("requested end: %1"), partition_new . sector_end ) + "\n" +
 
2319
                                String::ucompose( _("requested size: %1 (%2)"),
 
2320
                                                partition_new .get_sector_length(),
 
2321
                                                Utils::format_size( partition_new .get_sector_length(), partition_new .sector_size ) ),
 
2322
                                                                STATUS_NONE,
 
2323
                                                                FONT_ITALIC )
 
2324
                                                                ) ;
 
2325
        }
 
2326
 
 
2327
        operationdetail .get_last_child() .set_status( return_value ? STATUS_SUCCES : STATUS_ERROR ) ;
 
2328
        
 
2329
        return return_value ;
 
2330
}
 
2331
 
 
2332
bool GParted_Core::resize_filesystem( const Partition & partition_old,
 
2333
                                      const Partition & partition_new,
 
2334
                                      OperationDetail & operationdetail,
 
2335
                                      bool fill_partition ) 
 
2336
{
 
2337
        //by default 'grow' to accomodate expand_filesystem()
 
2338
        GParted::FS::Support action = get_fs( partition_old .filesystem ) .grow ;
 
2339
 
 
2340
        if ( ! fill_partition )
 
2341
        {
 
2342
                if ( partition_new .get_sector_length() < partition_old .get_sector_length() )
 
2343
                {
 
2344
                        operationdetail .add_child( OperationDetail( _("shrink file system") ) ) ;
 
2345
                        action = get_fs( partition_old .filesystem ) .shrink ;
 
2346
                }
 
2347
                else if ( partition_new .get_sector_length() > partition_old .get_sector_length() )
 
2348
                        operationdetail .add_child( OperationDetail( _("grow file system") ) ) ;
 
2349
                else
 
2350
                {
 
2351
                        operationdetail .add_child( OperationDetail( _("resize file system") ) ) ;
 
2352
                        operationdetail .get_last_child() .add_child( 
 
2353
                                OperationDetail( 
 
2354
                                        _("new and old file system have the same size.  Hence skipping this operation"),
 
2355
                                        STATUS_NONE,
 
2356
                                        FONT_ITALIC ) ) ;
 
2357
                
 
2358
                        operationdetail .get_last_child() .set_status( STATUS_SUCCES ) ;
 
2359
                        return true ;
 
2360
                }
 
2361
        }
 
2362
 
 
2363
        bool succes = false ;
 
2364
        switch ( action )
 
2365
        {
 
2366
                case GParted::FS::NONE:
 
2367
                        break ;
 
2368
                case GParted::FS::GPARTED:
 
2369
                        break ;
 
2370
#ifdef HAVE_LIBPARTED_FS_RESIZE
 
2371
                case GParted::FS::LIBPARTED:
 
2372
                        succes = resize_move_filesystem_using_libparted( partition_old,
 
2373
                                                                         partition_new,
 
2374
                                                                         operationdetail .get_last_child() ) ;
 
2375
                        break ;
 
2376
#endif
 
2377
                case GParted::FS::EXTERNAL:
 
2378
                        succes = set_proper_filesystem( partition_new .filesystem ) && 
 
2379
                                 p_filesystem ->resize( partition_new,
 
2380
                                                        operationdetail .get_last_child(), 
 
2381
                                                        fill_partition ) ;
 
2382
                        break ;
 
2383
 
 
2384
                default:
 
2385
                        break ;
 
2386
        }
 
2387
 
 
2388
        operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
2389
        return succes ;
 
2390
}
 
2391
        
 
2392
bool GParted_Core::maximize_filesystem( const Partition & partition, OperationDetail & operationdetail ) 
 
2393
{
 
2394
        operationdetail .add_child( OperationDetail( _("grow file system to fill the partition") ) ) ;
 
2395
 
 
2396
        if ( get_fs( partition .filesystem ) .grow == GParted::FS::NONE )
 
2397
        {
 
2398
                operationdetail .get_last_child() .add_child( 
 
2399
                        OperationDetail( _("growing is not available for this file system"),
 
2400
                                          STATUS_NONE,
 
2401
                                          FONT_ITALIC ) ) ;
 
2402
 
 
2403
                operationdetail .get_last_child() .set_status( STATUS_N_A ) ;
 
2404
                return true ;
 
2405
        }
 
2406
        
 
2407
        return resize_filesystem( partition, partition, operationdetail, true ) ;
 
2408
}
 
2409
 
 
2410
bool GParted_Core::copy( const Partition & partition_src,
 
2411
                         Partition & partition_dst,
 
2412
                         Byte_Value min_size,
 
2413
                         OperationDetail & operationdetail ) 
 
2414
{
 
2415
        if (   partition_dst .get_byte_length() < partition_src .get_byte_length()
 
2416
            && partition_src .filesystem != FS_XFS // Permit copying to smaller xfs partition
 
2417
           )
 
2418
        {
 
2419
                operationdetail .add_child( OperationDetail( 
 
2420
                        _("the destination is smaller than the source partition"), STATUS_ERROR, FONT_ITALIC ) ) ;
 
2421
 
 
2422
                return false ;
 
2423
        }
 
2424
 
 
2425
        if ( check_repair_filesystem( partition_src, operationdetail ) )
 
2426
        {
 
2427
                bool succes = true ;
 
2428
                if ( partition_dst .status == GParted::STAT_COPY )
 
2429
                {
 
2430
                        /* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
 
2431
                        succes = create_partition( partition_dst, operationdetail, ( (min_size + (partition_dst .sector_size - 1)) / partition_dst .sector_size ) ) ;
 
2432
                }
 
2433
 
 
2434
                if ( succes && set_partition_type( partition_dst, operationdetail ) )
 
2435
                {
 
2436
                        operationdetail .add_child( OperationDetail( 
 
2437
                                String::ucompose( _("copy file system of %1 to %2"),
 
2438
                                                  partition_src .get_path(),
 
2439
                                                  partition_dst .get_path() ) ) ) ;
 
2440
                                                
 
2441
                        switch ( get_fs( partition_dst .filesystem ) .copy )
 
2442
                        {
 
2443
                                case GParted::FS::GPARTED :
 
2444
                                                succes = copy_filesystem( partition_src,
 
2445
                                                                          partition_dst,
 
2446
                                                                          operationdetail .get_last_child() ) ;
 
2447
                                                break ;
 
2448
 
 
2449
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
 
2450
                                case GParted::FS::LIBPARTED :
 
2451
                                                //FIXME: see if copying through libparted has any advantages
 
2452
                                                break ;
 
2453
#endif
 
2454
 
 
2455
                                case GParted::FS::EXTERNAL :
 
2456
                                                succes = set_proper_filesystem( partition_dst .filesystem ) &&
 
2457
                                                         p_filesystem ->copy( partition_src .get_path(),
 
2458
                                                                              partition_dst .get_path(),
 
2459
                                                                              operationdetail .get_last_child() ) ;
 
2460
                                                break ;
 
2461
 
 
2462
                                default :
 
2463
                                                succes = false ;
 
2464
                                                break ;
 
2465
                        }
 
2466
 
 
2467
                        operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
2468
 
 
2469
                        return (   succes
 
2470
                                && update_bootsector( partition_dst, operationdetail )
 
2471
                                && (   //Do not maximize file system if FS not linux-swap and destination size <= source
 
2472
                                       (   partition_dst .filesystem != FS_LINUX_SWAP  //linux-swap is recreated, not copied
 
2473
                                        && partition_dst .get_sector_length() <= partition_src .get_sector_length()
 
2474
                                       )
 
2475
                                    || (   check_repair_filesystem( partition_dst, operationdetail )
 
2476
                                        && maximize_filesystem( partition_dst, operationdetail )
 
2477
                                       )
 
2478
                                   )
 
2479
                               );
 
2480
                }
 
2481
        }
 
2482
 
 
2483
        return false ;
 
2484
}
 
2485
 
 
2486
bool GParted_Core::copy_filesystem_simulation( const Partition & partition_src,
 
2487
                                               const Partition & partition_dst,
 
2488
                                               OperationDetail & operationdetail ) 
 
2489
{
 
2490
        operationdetail .add_child( OperationDetail( _("perform read-only test") ) ) ;
 
2491
        
 
2492
        bool succes = copy_filesystem( partition_src, partition_dst, operationdetail .get_last_child(), true ) ;
 
2493
 
 
2494
        operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
2495
        return succes ;
 
2496
}
 
2497
 
 
2498
bool GParted_Core::copy_filesystem( const Partition & partition_src,
 
2499
                                    const Partition & partition_dst,
 
2500
                                    OperationDetail & operationdetail,
 
2501
                                    bool readonly )
 
2502
{
 
2503
        Sector dummy ;
 
2504
        return copy_filesystem( partition_src .device_path,
 
2505
                                partition_dst .device_path,
 
2506
                                partition_src .sector_start,
 
2507
                                partition_dst .sector_start,
 
2508
                                partition_src .sector_size,
 
2509
                                partition_dst .sector_size,
 
2510
                                partition_src .get_byte_length(),
 
2511
                                operationdetail,
 
2512
                                readonly,
 
2513
                                dummy ) ;
 
2514
}
 
2515
 
 
2516
bool GParted_Core::copy_filesystem( const Partition & partition_src,
 
2517
                                    const Partition & partition_dst,
 
2518
                                    OperationDetail & operationdetail,
 
2519
                                    Byte_Value & total_done ) 
 
2520
{
 
2521
        return copy_filesystem( partition_src .device_path,
 
2522
                                partition_dst .device_path,
 
2523
                                partition_src .sector_start,
 
2524
                                partition_dst .sector_start,
 
2525
                                partition_src .sector_size,
 
2526
                                partition_dst .sector_size,
 
2527
                                partition_src .get_byte_length(),
 
2528
                                operationdetail,
 
2529
                                false,
 
2530
                                total_done ) ;
 
2531
}
 
2532
        
 
2533
bool GParted_Core::copy_filesystem( const Glib::ustring & src_device,
 
2534
                                    const Glib::ustring & dst_device,
 
2535
                                    Sector src_start,
 
2536
                                    Sector dst_start,
 
2537
                                    Byte_Value src_sector_size,
 
2538
                                    Byte_Value dst_sector_size,
 
2539
                                    Byte_Value src_length,
 
2540
                                    OperationDetail & operationdetail,
 
2541
                                    bool readonly,
 
2542
                                    Byte_Value & total_done ) 
 
2543
{
 
2544
        operationdetail .add_child( OperationDetail( _("using internal algorithm"), STATUS_NONE ) ) ;
 
2545
        operationdetail .add_child( OperationDetail( 
 
2546
                String::ucompose( readonly ?
 
2547
                                /*TO TRANSLATORS: looks like  read 1.00 MiB */
 
2548
                                _("read %1") :
 
2549
                                /*TO TRANSLATORS: looks like  copy 1.00 MiB */
 
2550
                                _("copy %1"),
 
2551
                                Utils::format_size( src_length, 1 ) ),
 
2552
                                STATUS_NONE ) ) ;
 
2553
 
 
2554
        operationdetail .add_child( OperationDetail( _("finding optimal block size"), STATUS_NONE ) ) ;
 
2555
 
 
2556
        Byte_Value benchmark_blocksize = readonly ? (2 * MEBIBYTE) : (1 * MEBIBYTE), N = (16 * MEBIBYTE) ;
 
2557
        Byte_Value optimal_blocksize = benchmark_blocksize ;
 
2558
        Sector offset_read = src_start ;
 
2559
        Sector offset_write = dst_start ;
 
2560
 
 
2561
        //Handle situation where we need to perform the copy beginning
 
2562
        //  with the end of the partition and finishing with the start.
 
2563
        if ( dst_start > src_start )
 
2564
        {
 
2565
                offset_read  += (src_length/src_sector_size) - (N/src_sector_size) ;
 
2566
                /* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
 
2567
                offset_write += ((src_length + (dst_sector_size - 1))/dst_sector_size) - (N/dst_sector_size) ;
 
2568
        }
 
2569
 
 
2570
        total_done = 0 ;
 
2571
        Byte_Value done = 0 ;
 
2572
        Glib::Timer timer ;
 
2573
        double smallest_time = 1000000 ;
 
2574
        bool succes = true ;
 
2575
 
 
2576
        //Benchmark copy times using different block sizes to determine optimal size
 
2577
        while ( succes &&
 
2578
                llabs( done ) + N <= src_length && 
 
2579
                benchmark_blocksize <= N )
 
2580
        {
 
2581
                timer .reset() ;
 
2582
                succes = copy_blocks( src_device, 
 
2583
                                      dst_device,
 
2584
                                      offset_read  + (done / src_sector_size),
 
2585
                                      offset_write + (done / dst_sector_size),
 
2586
                                      N,
 
2587
                                      benchmark_blocksize,
 
2588
                                      operationdetail .get_last_child(),
 
2589
                                      readonly,
 
2590
                                      total_done ) ;
 
2591
                timer.stop() ;
 
2592
 
 
2593
                operationdetail .get_last_child() .get_last_child() .add_child( OperationDetail( 
 
2594
                        String::ucompose( _("%1 seconds"), timer .elapsed() ), STATUS_NONE, FONT_ITALIC ) ) ;
 
2595
 
 
2596
                if ( timer .elapsed() <= smallest_time )
 
2597
                {
 
2598
                        smallest_time = timer .elapsed() ;
 
2599
                        optimal_blocksize = benchmark_blocksize ; 
 
2600
                }
 
2601
                benchmark_blocksize *= 2 ;
 
2602
 
 
2603
                if ( ( dst_start > src_start ) )
 
2604
                        done -= N ;
 
2605
                else
 
2606
                        done += N ;
 
2607
        }
 
2608
        
 
2609
        if ( succes )
 
2610
                operationdetail .get_last_child() .add_child( OperationDetail( String::ucompose( 
 
2611
                                /*TO TRANSLATORS: looks like  optimal block size is 1.00 MiB */
 
2612
                                _("optimal block size is %1"),
 
2613
                                Utils::format_size( optimal_blocksize, 1 ) ),
 
2614
                                STATUS_NONE ) ) ;
 
2615
 
 
2616
        if ( succes && llabs( done ) < src_length )
 
2617
                succes = copy_blocks( src_device, 
 
2618
                                    dst_device,
 
2619
                                    src_start + ( dst_start > src_start ? 0 : (done / src_sector_size) ),
 
2620
                                    dst_start + ( dst_start > src_start ? 0 : (done / dst_sector_size) ),
 
2621
                                    src_length - llabs( done ),
 
2622
                                    optimal_blocksize,
 
2623
                                    operationdetail,
 
2624
                                    readonly,
 
2625
                                    total_done ) ;
 
2626
 
 
2627
        operationdetail .add_child( OperationDetail( 
 
2628
                String::ucompose( readonly ?
 
2629
                                /*TO TRANSLATORS: looks like  1.00 MiB (1048576 B) read */
 
2630
                                _("%1 (%2 B) read") :
 
2631
                                /*TO TRANSLATORS: looks like  1.00 MiB (1048576 B) copied */
 
2632
                                _("%1 (%2 B) copied"),
 
2633
                                Utils::format_size( total_done, 1 ), total_done ),
 
2634
                                STATUS_NONE ) ) ;
 
2635
        return succes ;
 
2636
}
 
2637
 
 
2638
void GParted_Core::rollback_transaction( const Partition & partition_src,
 
2639
                                         const Partition & partition_dst,
 
2640
                                         OperationDetail & operationdetail,
 
2641
                                         Byte_Value total_done )
 
2642
{
 
2643
        if ( total_done > 0 )
 
2644
        {
 
2645
                operationdetail .add_child( OperationDetail( _("roll back last transaction") ) ) ;
 
2646
 
 
2647
                //find out exactly which part of the file system was copied (and to where it was copied)..
 
2648
                Partition temp_src = partition_src ;
 
2649
                Partition temp_dst = partition_dst ;
 
2650
 
 
2651
                if ( partition_dst .sector_start > partition_src .sector_start )
 
2652
                {
 
2653
                        temp_src .sector_start = temp_src .sector_end - ( (total_done / temp_src .sector_size) - 1 ) ;
 
2654
                        temp_dst .sector_start = temp_dst .sector_end - ( (total_done / temp_dst .sector_size) - 1 ) ;
 
2655
                }
 
2656
                else
 
2657
                {
 
2658
                        temp_src .sector_end = temp_src .sector_start + ( (total_done / temp_src .sector_size) - 1 ) ;
 
2659
                        temp_dst .sector_end = temp_dst .sector_start + ( (total_done / temp_dst .sector_size) - 1 ) ;
 
2660
                }
 
2661
 
 
2662
                //and copy it back (NOTE the reversed dst and src)
 
2663
                bool succes = copy_filesystem( temp_dst, temp_src, operationdetail .get_last_child() ) ;
 
2664
 
 
2665
                operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
2666
        }
 
2667
}
 
2668
 
 
2669
bool GParted_Core::check_repair_filesystem( const Partition & partition, OperationDetail & operationdetail ) 
 
2670
{
 
2671
        operationdetail .add_child( OperationDetail( 
 
2672
                                String::ucompose(
 
2673
                                                /* TO TRANSLATORS: looks like   check file system on /dev/sda5 for errors and (if possible) fix them */
 
2674
                                                _("check file system on %1 for errors and (if possible) fix them"),
 
2675
                                                  partition .get_path() ) ) ) ;
 
2676
        
 
2677
        bool succes = false ;
 
2678
        switch ( get_fs( partition .filesystem ) .check )
 
2679
        {
 
2680
                case GParted::FS::NONE:
 
2681
                        operationdetail .get_last_child() .add_child(
 
2682
                                OperationDetail( _("checking is not available for this file system"),
 
2683
                                                 STATUS_NONE,
 
2684
                                                 FONT_ITALIC ) ) ;
 
2685
 
 
2686
                        operationdetail .get_last_child() .set_status( STATUS_N_A ) ;
 
2687
                        return true ;   
 
2688
 
 
2689
                        break ;
 
2690
                case GParted::FS::GPARTED:
 
2691
                        break ;
 
2692
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
 
2693
                case GParted::FS::LIBPARTED:
 
2694
                        break ;
 
2695
#endif
 
2696
                case GParted::FS::EXTERNAL:
 
2697
                        succes = set_proper_filesystem( partition .filesystem ) &&
 
2698
                                 p_filesystem ->check_repair( partition, operationdetail .get_last_child() ) ;
 
2699
 
 
2700
                        break ;
 
2701
 
 
2702
                default:
 
2703
                        break ;
 
2704
        }
 
2705
 
 
2706
        operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
2707
        return succes ;
 
2708
}
 
2709
 
 
2710
bool GParted_Core::set_partition_type( const Partition & partition, OperationDetail & operationdetail )
 
2711
{
 
2712
        operationdetail .add_child( OperationDetail(
 
2713
                                String::ucompose( _("set partition type on %1"), partition .get_path() ) ) ) ;
 
2714
        
 
2715
        bool return_value = false ;
 
2716
        
 
2717
        if ( open_device_and_disk( partition .device_path ) )
 
2718
        {
 
2719
                PedFileSystemType * fs_type = 
 
2720
                        ped_file_system_type_get( Utils::get_filesystem_string( partition .filesystem ) .c_str() ) ;
 
2721
 
 
2722
                //If not found, and FS is linux-swap, then try linux-swap(v1)
 
2723
                if ( ! fs_type && Utils::get_filesystem_string( partition .filesystem ) == "linux-swap" )
 
2724
                        fs_type = ped_file_system_type_get( "linux-swap(v1)" ) ;
 
2725
 
 
2726
                //If not found, and FS is linux-swap, then try linux-swap(new)
 
2727
                if ( ! fs_type && Utils::get_filesystem_string( partition .filesystem ) == "linux-swap" )
 
2728
                        fs_type = ped_file_system_type_get( "linux-swap(new)" ) ;
 
2729
 
 
2730
                //default is Linux (83)
 
2731
                if ( ! fs_type )
 
2732
                        fs_type = ped_file_system_type_get( "ext2" ) ;
 
2733
 
 
2734
                if ( fs_type )
 
2735
                {
 
2736
                        lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
 
2737
 
 
2738
                        if ( lp_partition &&
 
2739
                             ped_partition_set_system( lp_partition, fs_type ) && 
 
2740
                             commit() )
 
2741
                        {
 
2742
                                operationdetail .get_last_child() .add_child( 
 
2743
                                        OperationDetail( String::ucompose( _("new partition type: %1"),
 
2744
                                                                           lp_partition ->fs_type ->name ),
 
2745
                                                         STATUS_NONE,
 
2746
                                                         FONT_ITALIC ) ) ;
 
2747
 
 
2748
                                return_value = true ;
 
2749
                        }
 
2750
                }
 
2751
 
 
2752
                close_device_and_disk() ;
 
2753
        }
 
2754
 
 
2755
        operationdetail .get_last_child() .set_status( return_value ? STATUS_SUCCES : STATUS_ERROR ) ;
 
2756
        return return_value ;
 
2757
}
 
2758
        
 
2759
void GParted_Core::set_progress_info( Byte_Value total,
 
2760
                                      Byte_Value done,
 
2761
                                      const Glib::Timer & timer,
 
2762
                                      OperationDetail & operationdetail,
 
2763
                                      bool readonly ) 
 
2764
{
 
2765
        operationdetail .fraction = done / static_cast<double>( total ) ;
 
2766
 
 
2767
        std::time_t time_remaining = Utils::round( (total - done) / ( done / timer .elapsed() ) ) ;
 
2768
 
 
2769
        operationdetail .progress_text = 
 
2770
                String::ucompose( readonly ?
 
2771
                                /*TO TRANSLATORS: looks like  1.00 MiB of 16.00 MiB read (00:01:59 remaining) */
 
2772
                                _("%1 of %2 read (%3 remaining)") :
 
2773
                                /*TO TRANSLATORS: looks like  1.00 MiB of 16.00 MiB copied (00:01:59 remaining) */
 
2774
                                _("%1 of %2 copied (%3 remaining)"),
 
2775
                                  Utils::format_size( done, 1 ),
 
2776
                                  Utils::format_size( total,1 ),
 
2777
                                  Utils::format_time( time_remaining) ) ; 
 
2778
                        
 
2779
        operationdetail .set_description( 
 
2780
                String::ucompose( readonly ?
 
2781
                                /*TO TRANSLATORS: looks like  1.00 MiB of 16.00 MiB read */
 
2782
                                _("%1 of %2 read") :
 
2783
                                /*TO TRANSLATORS: looks like  1.00 MiB of 16.00 MiB copied */
 
2784
                                _("%1 of %2 copied"),
 
2785
                                Utils::format_size( done, 1 ), Utils::format_size( total, 1 ) ),
 
2786
                                FONT_ITALIC ) ;
 
2787
}
 
2788
        
 
2789
bool GParted_Core::copy_blocks( const Glib::ustring & src_device,
 
2790
                                const Glib::ustring & dst_device,
 
2791
                                Sector src_start,
 
2792
                                Sector dst_start,
 
2793
                                Byte_Value length,
 
2794
                                Byte_Value blocksize,
 
2795
                                OperationDetail & operationdetail,
 
2796
                                bool readonly,
 
2797
                                Byte_Value & total_done ) 
 
2798
{
 
2799
        if ( blocksize > length )
 
2800
                blocksize = length ;
 
2801
 
 
2802
        if ( readonly )
 
2803
                operationdetail .add_child( OperationDetail( 
 
2804
                                /*TO TRANSLATORS: looks like  read 16.00 MiB using a block size of 1.00 MiB */
 
2805
                                String::ucompose( _("read %1 using a block size of %2"), Utils::format_size( length, 1 ),
 
2806
                                        Utils::format_size( blocksize, 1 ) ) ) ) ;
 
2807
        else
 
2808
                operationdetail .add_child( OperationDetail( 
 
2809
                                /*TO TRANSLATORS: looks like  copy 16.00 MiB using a block size of 1.00 MiB */
 
2810
                                String::ucompose( _("copy %1 using a block size of %2"), Utils::format_size( length, 1 ),
 
2811
                                        Utils::format_size( blocksize, 1 ) ) ) ) ;
 
2812
 
 
2813
        Byte_Value done = length % blocksize ; 
 
2814
 
 
2815
        bool succes = false ;
 
2816
        PedDevice *lp_device_src = ped_device_get( src_device .c_str() );
 
2817
        PedDevice *lp_device_dst = src_device != dst_device ? ped_device_get( dst_device .c_str() ) : lp_device_src ;
 
2818
 
 
2819
        if ( lp_device_src && lp_device_dst && ped_device_open( lp_device_src ) && ped_device_open( lp_device_dst ) )
 
2820
        {
 
2821
                Byte_Value src_sector_size = lp_device_src ->sector_size ;
 
2822
                Byte_Value dst_sector_size = lp_device_dst ->sector_size ;
 
2823
 
 
2824
                //Handle situation where we need to perform the copy beginning
 
2825
                //  with the end of the partition and finishing with the start.
 
2826
                if ( dst_start > src_start )
 
2827
                {
 
2828
                        blocksize -= 2*blocksize ;
 
2829
                        done -= 2*done ;
 
2830
                        src_start += ( (length / src_sector_size) - 1 ) ;
 
2831
                        /* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
 
2832
                        dst_start += ( ((length + (dst_sector_size - 1))/ dst_sector_size) - 1 ) ;
 
2833
                }
 
2834
 
 
2835
                Glib::ustring error_message ;
 
2836
                buf = static_cast<char *>( malloc( llabs( blocksize ) ) ) ;
 
2837
                if ( buf )
 
2838
                {
 
2839
                        ped_device_sync( lp_device_dst ) ;
 
2840
 
 
2841
                        succes = true ;
 
2842
                        if ( done != 0 )
 
2843
                                succes = copy_block( lp_device_src,
 
2844
                                                lp_device_dst,
 
2845
                                                src_start,
 
2846
                                                dst_start, 
 
2847
                                                done,
 
2848
                                                error_message,
 
2849
                                                readonly ) ;
 
2850
                        if ( ! succes )
 
2851
                                done = 0 ;
 
2852
 
 
2853
                        //add an empty sub which we will constantly update in the loop
 
2854
                        operationdetail .get_last_child() .add_child( OperationDetail( "", STATUS_NONE ) ) ;
 
2855
 
 
2856
                        Glib::Timer timer_progress_timeout, timer_total ;
 
2857
                        while( succes && llabs( done ) < length )
 
2858
                        {
 
2859
                                succes = copy_block( lp_device_src,
 
2860
                                                     lp_device_dst,
 
2861
                                                     src_start + (done / src_sector_size),
 
2862
                                                     dst_start + (done / dst_sector_size),
 
2863
                                                     blocksize,
 
2864
                                                     error_message,
 
2865
                                                     readonly ) ; 
 
2866
                                if ( succes )
 
2867
                                        done += blocksize ;
 
2868
 
 
2869
                                if ( timer_progress_timeout .elapsed() >= 0.5 )
 
2870
                                {
 
2871
                                        set_progress_info( length,
 
2872
                                                           llabs( done + blocksize ),
 
2873
                                                           timer_total,
 
2874
                                                           operationdetail .get_last_child() .get_last_child(),
 
2875
                                                           readonly ) ;
 
2876
                        
 
2877
                                        timer_progress_timeout .reset() ;
 
2878
                                }
 
2879
                        }
 
2880
                        //set progress bar current info on completion
 
2881
                        set_progress_info( length,
 
2882
                                           llabs( done ),
 
2883
                                           timer_total,
 
2884
                                           operationdetail .get_last_child() .get_last_child(),
 
2885
                                           readonly ) ;
 
2886
                        
 
2887
                        free( buf ) ;
 
2888
                }
 
2889
                else
 
2890
                        error_message = Glib::strerror( errno ) ;
 
2891
 
 
2892
                //reset fraction to -1 to make room for a new one (or a pulsebar)
 
2893
                operationdetail .get_last_child() .get_last_child() .fraction = -1 ;
 
2894
 
 
2895
                //final description
 
2896
                operationdetail .get_last_child() .get_last_child() .set_description( 
 
2897
                        String::ucompose( readonly ?
 
2898
                                        /*TO TRANSLATORS: looks like  1.00 MiB of 16.00 MiB read */
 
2899
                                        _("%1 of %2 read") :
 
2900
                                        /*TO TRANSLATORS: looks like  1.00 MiB of 16.00 MiB copied */
 
2901
                                        _("%1 of %2 copied"),
 
2902
                                        Utils::format_size( llabs( done ), 1 ),
 
2903
                                        Utils::format_size( length, 1 ) ),
 
2904
                                        FONT_ITALIC ) ;
 
2905
                
 
2906
                if ( ! succes && ! error_message .empty() )
 
2907
                        operationdetail .get_last_child() .add_child( 
 
2908
                                OperationDetail( error_message, STATUS_NONE, FONT_ITALIC ) ) ;
 
2909
                
 
2910
                total_done += llabs( done ) ;
 
2911
        
 
2912
                //close and destroy the devices..
 
2913
                ped_device_close( lp_device_src ) ;
 
2914
                ped_device_destroy( lp_device_src ) ; 
 
2915
 
 
2916
                if ( src_device != dst_device )
 
2917
                {
 
2918
                        ped_device_close( lp_device_dst ) ;
 
2919
                        ped_device_destroy( lp_device_dst ) ;
 
2920
                }
 
2921
        }
 
2922
 
 
2923
        operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
2924
        return succes ;
 
2925
}
 
2926
 
 
2927
bool GParted_Core::copy_block( PedDevice * lp_device_src,
 
2928
                               PedDevice * lp_device_dst,
 
2929
                               Sector offset_src,
 
2930
                               Sector offset_dst,
 
2931
                               Byte_Value block_length,
 
2932
                               Glib::ustring & error_message,
 
2933
                               bool readonly ) 
 
2934
{
 
2935
        Byte_Value sector_size_src = lp_device_src ->sector_size ;
 
2936
        Byte_Value sector_size_dst = lp_device_dst ->sector_size ;
 
2937
 
 
2938
        //Handle case where src and dst sector sizes are different.
 
2939
        //    E.g.,  5 sectors x 512 bytes/sector = ??? 2048 byte sectors
 
2940
        Sector num_blocks_src = (llabs(block_length) + (sector_size_src - 1) ) / sector_size_src ;
 
2941
        Sector num_blocks_dst = (llabs(block_length) + (sector_size_dst - 1) ) / sector_size_dst ;
 
2942
 
 
2943
        //Handle situation where we are performing copy operation beginning
 
2944
        //  with the end of the partition and finishing with the start.
 
2945
        if ( block_length < 0 )
 
2946
        {
 
2947
                block_length = llabs( block_length ) ;
 
2948
                offset_src -= ( (block_length / sector_size_src) - 1 ) ;
 
2949
                /* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
 
2950
                offset_dst -= ( ( (block_length + (sector_size_dst - 1)) / sector_size_dst) - 1 ) ;
 
2951
        }
 
2952
 
 
2953
        if ( block_length != 0 )
 
2954
        {
 
2955
                if ( ped_device_read( lp_device_src, buf, offset_src, num_blocks_src ) )
 
2956
                {
 
2957
                        if ( readonly || ped_device_write( lp_device_dst, buf, offset_dst, num_blocks_dst ) )
 
2958
                                return true ;
 
2959
                        else
 
2960
                                error_message = String::ucompose( _("Error while writing block at sector %1"), offset_dst ) ;
 
2961
                }
 
2962
                else
 
2963
                        error_message = String::ucompose( _("Error while reading block at sector %1"), offset_src ) ;
 
2964
        }
 
2965
 
 
2966
        return false ;
 
2967
}
 
2968
 
 
2969
bool GParted_Core::calibrate_partition( Partition & partition, OperationDetail & operationdetail ) 
 
2970
{
 
2971
        if ( partition .type == TYPE_PRIMARY || partition .type == TYPE_LOGICAL || partition .type == TYPE_EXTENDED )
 
2972
        {
 
2973
                operationdetail .add_child( OperationDetail( String::ucompose( _("calibrate %1"), partition .get_path() ) ) ) ;
 
2974
        
 
2975
                bool succes = false ;
 
2976
                if ( open_device_and_disk( partition .device_path ) )
 
2977
                {       
 
2978
                        if ( partition .type == GParted::TYPE_EXTENDED )
 
2979
                                lp_partition = ped_disk_extended_partition( lp_disk ) ;
 
2980
                        else    
 
2981
                                lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
 
2982
                
 
2983
                        if ( lp_partition )//FIXME: add check to see if lp_partition ->type matches partition .type..
 
2984
                        {
 
2985
                                partition .add_path( get_partition_path( lp_partition ) ) ;
 
2986
 
 
2987
                                partition .sector_start = lp_partition ->geom .start ;
 
2988
                                partition .sector_end = lp_partition ->geom .end ;
 
2989
 
 
2990
                                operationdetail .get_last_child() .add_child( 
 
2991
                                        OperationDetail(
 
2992
                                                String::ucompose( _("path: %1"), partition .get_path() ) + "\n" +
 
2993
                                                String::ucompose( _("start: %1"), partition .sector_start ) + "\n" +
 
2994
                                                String::ucompose( _("end: %1"), partition .sector_end ) + "\n" +
 
2995
                                                String::ucompose( _("size: %1 (%2)"),
 
2996
                                                                partition .get_sector_length(),
 
2997
                                                                Utils::format_size( partition .get_sector_length(), partition .sector_size ) ),
 
2998
                                        STATUS_NONE, 
 
2999
                                        FONT_ITALIC ) ) ;
 
3000
                                succes = true ;
 
3001
                        }
 
3002
 
 
3003
                        close_device_and_disk() ;
 
3004
                }
 
3005
 
 
3006
                operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
3007
                return succes ;
 
3008
        }
 
3009
        else //nothing to calibrate...
 
3010
                return true ;
 
3011
}
 
3012
 
 
3013
bool GParted_Core::calculate_exact_geom( const Partition & partition_old,
 
3014
                                         Partition & partition_new,
 
3015
                                         OperationDetail & operationdetail ) 
 
3016
{
 
3017
        operationdetail .add_child( OperationDetail( 
 
3018
                String::ucompose( _("calculate new size and position of %1"), partition_new .get_path() ) ) ) ;
 
3019
 
 
3020
        operationdetail .get_last_child() .add_child( 
 
3021
                OperationDetail(
 
3022
                        String::ucompose( _("requested start: %1"), partition_new .sector_start ) + "\n" +
 
3023
                        String::ucompose( _("requested end: %1"), partition_new .sector_end ) + "\n" +
 
3024
                        String::ucompose( _("requested size: %1 (%2)"),
 
3025
                                        partition_new .get_sector_length(),
 
3026
                                        Utils::format_size( partition_new .get_sector_length(), partition_new .sector_size ) ),
 
3027
                STATUS_NONE,
 
3028
                FONT_ITALIC ) ) ;
 
3029
        
 
3030
        bool succes = false ;
 
3031
        if ( open_device_and_disk( partition_old .device_path ) )
 
3032
        {
 
3033
                lp_partition = NULL ;
 
3034
 
 
3035
                if ( partition_old .type == GParted::TYPE_EXTENDED )
 
3036
                        lp_partition = ped_disk_extended_partition( lp_disk ) ;
 
3037
                else            
 
3038
                        lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition_old .get_sector() ) ;
 
3039
 
 
3040
                if ( lp_partition )
 
3041
                {
 
3042
                        PedConstraint *constraint = NULL ;
 
3043
                        constraint = ped_constraint_any( lp_device ) ;
 
3044
                        
 
3045
                        if ( constraint )
 
3046
                        {
 
3047
                                //FIXME: if we insert a weird partitionnew geom here (e.g. start > end) 
 
3048
                                //ped_disk_set_partition_geom() will still return true (althoug an lp exception is written
 
3049
                                //to stdout.. see if this also affect create_partition and resize_move_partition
 
3050
                                //sended a patch to fix this to libparted list. will probably be in 1.7.2
 
3051
                                if ( ped_disk_set_partition_geom( lp_disk,
 
3052
                                                                  lp_partition,
 
3053
                                                                  constraint,
 
3054
                                                                  partition_new .sector_start,
 
3055
                                                                  partition_new .sector_end ) )
 
3056
                                {
 
3057
                                        partition_new .sector_start = lp_partition ->geom .start ;
 
3058
                                        partition_new .sector_end = lp_partition ->geom .end ;
 
3059
                                        succes = true ;
 
3060
                                }
 
3061
                                        
 
3062
                                ped_constraint_destroy( constraint );
 
3063
                        }
 
3064
                }
 
3065
 
 
3066
                close_device_and_disk() ;       
 
3067
        }
 
3068
 
 
3069
        if ( succes ) 
 
3070
        {
 
3071
                operationdetail .get_last_child() .add_child( 
 
3072
                        OperationDetail(
 
3073
                                String::ucompose( _("new start: %1"), partition_new .sector_start ) + "\n" +
 
3074
                                String::ucompose( _("new end: %1"), partition_new .sector_end ) + "\n" +
 
3075
                                String::ucompose( _("new size: %1 (%2)"),
 
3076
                                                partition_new .get_sector_length(),
 
3077
                                                Utils::format_size( partition_new .get_sector_length(), partition_new .sector_size ) ),
 
3078
                        STATUS_NONE,
 
3079
                        FONT_ITALIC ) ) ;
 
3080
 
 
3081
#ifndef USE_LIBPARTED_DMRAID
 
3082
                //Update dev mapper entry if partition is dmraid.
 
3083
                DMRaid dmraid ;
 
3084
                if ( succes && dmraid .is_dmraid_device( partition_new .device_path ) )
 
3085
                {
 
3086
                        //Open disk handle before and close after to prevent application crash.
 
3087
                        if ( open_device_and_disk( partition_new .device_path ) )
 
3088
                        {
 
3089
                                succes = dmraid .update_dev_map_entry( partition_new, operationdetail .get_last_child() ) ;
 
3090
                                close_device_and_disk() ;
 
3091
                        }
 
3092
                }
 
3093
#endif
 
3094
        }
 
3095
 
 
3096
        operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
3097
        return succes ;
 
3098
}
 
3099
 
 
3100
bool GParted_Core::set_proper_filesystem( const FILESYSTEM & filesystem )
 
3101
{
 
3102
        p_filesystem = get_filesystem_object( filesystem ) ;
 
3103
 
 
3104
        return p_filesystem ;
 
3105
}
 
3106
 
 
3107
FileSystem * GParted_Core::get_filesystem_object( const FILESYSTEM & filesystem )
 
3108
{
 
3109
        if ( FILESYSTEM_MAP .count( filesystem ) )
 
3110
            return FILESYSTEM_MAP[ filesystem ] ;
 
3111
        else
 
3112
            return NULL ;
 
3113
}
 
3114
 
 
3115
#ifndef HAVE_LIBPARTED_3_0_0_PLUS
 
3116
bool GParted_Core::erase_filesystem_signatures( const Partition & partition ) 
 
3117
{
 
3118
        bool return_value = false ;
 
3119
        
 
3120
        if ( open_device_and_disk( partition .device_path ) )
 
3121
        {
 
3122
                lp_partition = ped_disk_get_partition_by_sector( lp_disk, partition .get_sector() ) ;
 
3123
 
 
3124
                if ( lp_partition && ped_file_system_clobber( & lp_partition ->geom ) )
 
3125
                {
 
3126
                        //file systems not yet supported by libparted
 
3127
                        if ( ped_device_open( lp_device ) )
 
3128
                        {
 
3129
                                //reiser4 stores "ReIsEr4" at sector 128 with a sector size of 512 bytes
 
3130
                                // FIXME writing block of partially uninitialized bytes (security/privacy)
 
3131
                                return_value = ped_geometry_write( & lp_partition ->geom, "0000000", (65536 / lp_device ->sector_size), 1 ) ;
 
3132
 
 
3133
                                ped_device_close( lp_device ) ;
 
3134
                        }
 
3135
                }
 
3136
                
 
3137
                close_device_and_disk() ;       
 
3138
        }
 
3139
 
 
3140
        return return_value ;
 
3141
}
 
3142
#endif
 
3143
 
 
3144
bool GParted_Core::update_bootsector( const Partition & partition, OperationDetail & operationdetail ) 
 
3145
{
 
3146
        //only for ntfs atm...
 
3147
        //FIXME: this should probably be done in the fs classes...
 
3148
        if ( partition .filesystem == FS_NTFS )
 
3149
        {
 
3150
                //The NTFS file system stores a value in the boot record called the
 
3151
                //  Number of Hidden Sectors.  This value must match the partition start
 
3152
                //  sector number in order for Windows to boot from the file system.
 
3153
                //  For more details, refer to the NTFS Volume Boot Record at:
 
3154
                //  http://www.geocities.com/thestarman3/asm/mbr/NTFSBR.htm
 
3155
 
 
3156
                operationdetail .add_child( OperationDetail( 
 
3157
                                /*TO TRANSLATORS: update boot sector of ntfs file system on /dev/sdd1 */
 
3158
                                String::ucompose( _("update boot sector of %1 file system on %2"),
 
3159
                                          Utils::get_filesystem_string( partition .filesystem ),
 
3160
                                          partition .get_path() ) ) ) ;
 
3161
 
 
3162
                //convert start sector to hex string
 
3163
                std::stringstream ss ;
 
3164
                ss << std::hex << partition .sector_start ;
 
3165
                Glib::ustring hex = ss .str() ;
 
3166
 
 
3167
                //fill with zeros and reverse...
 
3168
                hex .insert( 0, 8 - hex .length(), '0' ) ;
 
3169
                Glib::ustring reversed_hex ;
 
3170
                for ( int t = 6 ; t >= 0 ; t -=2 )
 
3171
                        reversed_hex .append( hex .substr( t, 2 ) ) ;
 
3172
 
 
3173
                //convert reversed hex codes into ascii characters
 
3174
                char buf[4] ;
 
3175
                for ( unsigned int k = 0; (k < 4 && k < (reversed_hex .length() / 2)); k++ )
 
3176
                {
 
3177
                        Glib::ustring tmp_hex = "0x" + reversed_hex .substr( k * 2, 2 ) ;
 
3178
                        buf[k] = (char)( std::strtol( tmp_hex .c_str(), NULL, 16 ) ) ;
 
3179
                }
 
3180
 
 
3181
                //write new Number of Hidden Sectors value into NTFS boot sector at offset 0x1C
 
3182
                Glib::ustring error_message = "" ;
 
3183
                std::ofstream dev_file ;
 
3184
                dev_file .open( partition .get_path() .c_str(), std::ios::out | std::ios::binary ) ;
 
3185
                if ( dev_file .is_open() )
 
3186
                {
 
3187
                        dev_file .seekp( 0x1C ) ;
 
3188
                        if ( dev_file .good() )
 
3189
                        {
 
3190
                                dev_file .write( buf, 4 ) ;
 
3191
                                if ( dev_file .bad() )
 
3192
                                {
 
3193
                                        /*TO TRANSLATORS: looks like Error trying to write to boot sector in /dev/sdd1 */
 
3194
                                        error_message = String::ucompose( _("Error trying to write to boot sector in %1"), partition .get_path() ) ;
 
3195
                                }
 
3196
                        }
 
3197
                        else
 
3198
                        {
 
3199
                                /*TO TRANSLATORS: looks like Error trying to seek to position 0x1C in /dev/sdd1 */
 
3200
                                error_message = String::ucompose( _("Error trying to seek to position 0x1c in %1"), partition .get_path() ) ;
 
3201
                        }
 
3202
                        dev_file .close( ) ;
 
3203
                }
 
3204
                else
 
3205
                {
 
3206
                        /*TO TRANSLATORS: looks like Error trying to open /dev/sdd1 */
 
3207
                        error_message = String::ucompose( _("Error trying to open %1"), partition .get_path() ) ;
 
3208
                }
 
3209
 
 
3210
                //append error messages if any found
 
3211
                bool succes = true ;
 
3212
                if ( ! error_message .empty() )
 
3213
                {
 
3214
                        succes = false ;
 
3215
                        error_message += "\n" ;
 
3216
                        /*TO TRANSLATORS: looks like Failed to set the number of hidden sectors to 05ab4f00 in the ntfs boot record. */
 
3217
                        error_message += String::ucompose( _("Failed to set the number of hidden sectors to %1 in the NTFS boot record."), reversed_hex ) ;
 
3218
                        error_message += "\n" ;
 
3219
                        error_message += String::ucompose( _("You might try the following command to correct the problem:"), reversed_hex ) ;
 
3220
                        error_message += "\n" ;
 
3221
                        error_message += String::ucompose( "echo %1 | xxd -r -p | dd conv=notrunc of=%2 bs=1 seek=28", reversed_hex, partition .get_path() ) ;
 
3222
                        operationdetail .get_last_child() .add_child( OperationDetail( error_message, STATUS_NONE, FONT_ITALIC ) ) ;
 
3223
                }
 
3224
 
 
3225
                operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
 
3226
                return succes ;
 
3227
        }
 
3228
 
 
3229
        return true ;
 
3230
}
 
3231
        
 
3232
bool GParted_Core::open_device( const Glib::ustring & device_path )
 
3233
{
 
3234
        lp_device = ped_device_get( device_path .c_str() );
 
3235
        
 
3236
        return lp_device ;
 
3237
}
 
3238
        
 
3239
bool GParted_Core::open_device_and_disk( const Glib::ustring & device_path, bool strict ) 
 
3240
{
 
3241
        lp_device = NULL ;
 
3242
        lp_disk = NULL ;
 
3243
 
 
3244
        if ( open_device( device_path ) )
 
3245
        {
 
3246
                lp_disk = ped_disk_new( lp_device );
 
3247
        
 
3248
                //if ! disk and writeable it's probably a HD without disklabel.
 
3249
                //We return true here and deal with them in GParted_Core::get_devices
 
3250
                if ( lp_disk || ( ! strict && ! lp_device ->read_only ) )
 
3251
                        return true ;
 
3252
                
 
3253
                close_device_and_disk() ;
 
3254
        }
 
3255
 
 
3256
        return false ;
 
3257
}
 
3258
 
 
3259
void GParted_Core::close_disk()
 
3260
{
 
3261
        if ( lp_disk )
 
3262
                ped_disk_destroy( lp_disk ) ;
 
3263
        
 
3264
        lp_disk = NULL ;
 
3265
}
 
3266
 
 
3267
void GParted_Core::close_device_and_disk()
 
3268
{
 
3269
        close_disk() ;
 
3270
 
 
3271
        if ( lp_device )
 
3272
                ped_device_destroy( lp_device ) ;
 
3273
                
 
3274
        lp_device = NULL ;
 
3275
}       
 
3276
 
 
3277
bool GParted_Core::commit() 
 
3278
{
 
3279
        bool succes = ped_disk_commit_to_dev( lp_disk ) ;
 
3280
        
 
3281
        succes = commit_to_os( 10 ) && succes ;
 
3282
 
 
3283
        return succes ;
 
3284
}
 
3285
 
 
3286
bool GParted_Core::commit_to_os( std::time_t timeout ) 
 
3287
{
 
3288
        bool succes ;
 
3289
#ifndef USE_LIBPARTED_DMRAID
 
3290
        DMRaid dmraid ;
 
3291
        if ( dmraid .is_dmraid_device( lp_disk ->dev ->path ) )
 
3292
                succes = true ;
 
3293
        else
 
3294
        {
 
3295
#endif
 
3296
                succes = ped_disk_commit_to_os( lp_disk ) ;
 
3297
#ifndef HAVE_LIBPARTED_2_2_0_PLUS
 
3298
                //Work around to try to alleviate problems caused by
 
3299
                //  bug #604298 - Failure to inform kernel of partition changes
 
3300
                //  If not successful the first time, try one more time.
 
3301
                if ( ! succes )
 
3302
                {
 
3303
                        sleep( 1 ) ;
 
3304
                        succes = ped_disk_commit_to_os( lp_disk ) ;
 
3305
                }
 
3306
#endif
 
3307
#ifndef USE_LIBPARTED_DMRAID
 
3308
        }
 
3309
#endif
 
3310
 
 
3311
        settle_device( timeout ) ;
 
3312
 
 
3313
        return succes ;
 
3314
}
 
3315
 
 
3316
void GParted_Core::settle_device( std::time_t timeout )
 
3317
{
 
3318
        if ( ! Glib::find_program_in_path( "udevsettle" ) .empty() )
 
3319
                Utils::execute_command( "udevsettle --timeout=" + Utils::num_to_str( timeout ) ) ;
 
3320
        else if ( ! Glib::find_program_in_path( "udevadm" ) .empty() )
 
3321
                Utils::execute_command( "udevadm settle --timeout=" + Utils::num_to_str( timeout ) ) ;
 
3322
        else
 
3323
                sleep( timeout ) ;
 
3324
}
 
3325
 
 
3326
class PedExceptionMsg : public Gtk::MessageDialog
 
3327
{
 
3328
public:
 
3329
        PedExceptionMsg( PedException &e ) : MessageDialog( Glib::ustring(e.message), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_NONE, true )
 
3330
                {
 
3331
                        switch( e.type )
 
3332
                        {
 
3333
                        case PED_EXCEPTION_WARNING:
 
3334
                                set_title( _("Libparted Warning") );
 
3335
                                property_message_type() = Gtk::MESSAGE_WARNING;
 
3336
                                break;
 
3337
                        case PED_EXCEPTION_INFORMATION:
 
3338
                                set_title( _("Libparted Information") );
 
3339
                                property_message_type() = Gtk::MESSAGE_INFO;
 
3340
                                break;
 
3341
                        case PED_EXCEPTION_ERROR:
 
3342
                                set_title( _("Libparted Error") );
 
3343
                        default:
 
3344
                                set_title( _("Libparted Bug Found!") );
 
3345
                        }
 
3346
                        if (e.options & PED_EXCEPTION_FIX)
 
3347
                                add_button( _("Fix"), PED_EXCEPTION_FIX );
 
3348
                        if (e.options & PED_EXCEPTION_YES)
 
3349
                                add_button( _("Yes"), PED_EXCEPTION_YES );
 
3350
                        if (e.options & PED_EXCEPTION_OK)
 
3351
                                add_button( _("Ok"), PED_EXCEPTION_OK );
 
3352
                        if (e.options & PED_EXCEPTION_RETRY)
 
3353
                                add_button( _("Retry"), PED_EXCEPTION_RETRY );
 
3354
                        if (e.options & PED_EXCEPTION_NO)
 
3355
                                add_button( _("No"), PED_EXCEPTION_NO );
 
3356
                        if (e.options & PED_EXCEPTION_CANCEL)
 
3357
                                add_button( _("Cancel"), PED_EXCEPTION_CANCEL );
 
3358
                        if (e.options & PED_EXCEPTION_IGNORE)
 
3359
                                add_button( _("Ignore"), PED_EXCEPTION_IGNORE );
 
3360
                }
 
3361
};
 
3362
 
 
3363
PedExceptionOption GParted_Core::ped_exception_handler( PedException * e ) 
 
3364
{
 
3365
        PedExceptionOption ret = PED_EXCEPTION_UNHANDLED;
 
3366
        std::cout << e ->message << std::endl ;
 
3367
 
 
3368
        libparted_messages .push_back( e->message ) ;
 
3369
        char optcount = 0;
 
3370
        int opt = 0;
 
3371
        for( char c = 0; c < 10; c++ )
 
3372
                if( e->options & (1 << c) ) {
 
3373
                        opt = (1 << c);
 
3374
                        optcount++;
 
3375
                }
 
3376
        // if only one option was given, choose it without popup
 
3377
        if( optcount == 1 && e->type != PED_EXCEPTION_BUG && e->type != PED_EXCEPTION_FATAL )
 
3378
                return (PedExceptionOption)opt;
 
3379
        if (Glib::Thread::self() != GParted_Core::mainthread)
 
3380
                gdk_threads_enter();
 
3381
        PedExceptionMsg msg( *e );
 
3382
        msg.show_all();
 
3383
        ret = (PedExceptionOption)msg.run();
 
3384
        if (Glib::Thread::self() != GParted_Core::mainthread)
 
3385
                gdk_threads_leave();
 
3386
        if (ret < 0)
 
3387
                ret = PED_EXCEPTION_UNHANDLED;
 
3388
        return ret;
 
3389
}
 
3390
 
 
3391
GParted_Core::~GParted_Core() 
 
3392
{
 
3393
        delete p_filesystem;
 
3394
}
 
3395
 
 
3396
Glib::Thread *GParted_Core::mainthread;
 
3397
        
 
3398
} //GParted