~ubuntu-branches/ubuntu/utopic/gparted/utopic-proposed

« back to all changes in this revision

Viewing changes to .pc/fix-swap.patch/src/GParted_Core.cc

  • Committer: Package Import Robot
  • Author(s): Phillip Susi
  • Date: 2012-02-21 10:11:00 UTC
  • Revision ID: package-import@ubuntu.com-20120221101100-f4zqpr9rlq23p4j9
Tags: 0.11.0-2
Add fix-swap.patch: fix regression where moving swap partitions
corrupted them by backporting upstream commit
93241cccbf4974a4a0ce4024cf94278f9ba3f386 LP: #935685

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