Commit Graph

804 Commits

Author SHA1 Message Date
Mike Fleetwood 307472489d Keep password dialog open until successful unlock or cancellation (#795617)
To keep password dialog open, just keep running it in a loop performing
LUKS mapping unlock attempts with the entered passphrase until it
succeeds or the dialog is cancelled or closed.  This is the same model
that is already used for the File Support System dialog and how the
[Rescan For Supported Actions] button is implemented.

Also any error from attempting to open the LUKS mapping is no longer
displayed in a separate error dialog or at all.  Will add some sort of
error reporting into the password entry dialog in a following commit.

Creates new method Win_GParted::open_encrypted_partition() which handles
the non UI parts of attempting to open an encrypted partition.  Running
"cryptsetup luksOpen" and updating the stored passphrase as needed.

Bug 795617 - Implement opening and closing of LUKS mappings
2018-04-30 09:10:48 -06:00
Mike Fleetwood f4d47fe5a5 Add password entry dialog and attempt LUKS unlock once (#795617)
Initial addition of a password entry dialog.  Looks like:

    +------------------------------------------------+
    |           LUKS Passphrase /dev/sdb1            |
    +------------------------------------------------+
    | Enter LUKS passphrase to open /dev/sdb1        |
    | Passphrase:    [                             ] |
    |                                                |
    |                          [ Cancel ] [ Unlock ] |
    +------------------------------------------------+

A standard Gtk Dialog is used to accept the password once, with any
errors displayed in a separate error dialog afterwards.  This is poor UI
design.  A password dialog should remain open for all authentication
attempts and only close when successful or the dialog is cancelled or
closed.  This UI design issue will be improved in following commits.

Bug 795617 - Implement opening and closing of LUKS mappings
2018-04-30 09:10:48 -06:00
Mike Fleetwood e4959c520f Add unimplemented open/close encryption to the partition menu (#795617)
Add new item to the partition menu to allow the user to open and close
the LUKS mapping.  However for now the menu item is always disabled and
there is no implementation behind it to actually open or close the LUKS
mapping.  Fragment of the partition menu is now:

    ...
    Format to       >
    -----------------
    Open Encryption      <- New menu item
    Mount
    -----------------
    Name Partition
    ...

Has to be two separate menu items to clearly represent to the user that
LUKS mappings and file system mounting are two separate busy states.
And also in the case of an open but unmounted file system to offer both
actions; close encryption and mount file system.

The text of the menu item automatically changes similarly to how it does
for the Mount/Unmount, Swapon/Swapoff, Activate/Deactivate item
depending on the state of the LUKS mapping.  For open LUKS mappings it
will show "Close Encryption" and for all other cases (closed LUKS
mapping or partition is not encrypted) "Open Encryption".  Again similar
to how the default of "Mount" is shown for unallocated and unknown
partitions.

Bug 795617 - Implement opening and closing of LUKS mappings
2018-04-30 09:10:48 -06:00
Mike Fleetwood f898910e90 Rename some Win_GParted members to *toggle_fs_busy* (#795617)
In preparation for adding the ability to toggle the encryption busy
state (open/close the encryption volume), rename existing members to
reflect that they are related to changing the file system state.  (Swap
and LVM2 Physical Volumes are handled as file systems by GParted).

class Win_GParted renaming:
    MENU_TOGGLE_BUSY             -> MENU_TOGGLE_FS_BUSY
    allow_toggle_busy_state()    -> allow_toggle_fs_busy_state()
    toggle_busy_state()          -> toggle_fs_busy_state()
    check_toggle_busy_allowed()  -> check_toggle_fs_busy_allowed()

Bug 795617 - Implement opening and closing of LUKS mappings
2018-04-30 09:10:48 -06:00
Mike Fleetwood 8dff80edc6 Add ability for small writes to stdin of child processes (#795617)
As discussed in "LUKS password handling, threats and preventative
measures" [1] GParted must be able to pass LUKS passphrases to
cryptsetup via standard input to avoid having to write passwords to the
file system and deal with additional security requirements.  Therefore
add a way to write input into created child processes.  For small
amounts of input, writing up to the pipe buffer capacity won't block
[2].  This is 64K on versions of Linux in any currently supported
distributions.

[1] LUKS password handling, threats and preventative measures
    https://bugzilla.gnome.org/show_bug.cgi?id=627701#c56

    GParted must not become a password manage so it must never save
    LUKS passwords to disk across separate invocations of GParted.
    ...

    GParted should avoid writing a temporary file containing the LUKS
    password as it introduces extra complexity with trying to safely
    handle and erase file content.  Instead GParted must
    programmatically pass the LUKS password via standard input to the
    cryptsetup command.

[2] pipe(7) manual page:

    Pipe capacity
        A pipe has a limited capacity.  If the pipe is full, then a
        write(2) will block or fail, depending on whether the O_NONBLOCK
        flag is set (see below).  ...

        In Linux versions before 2.6.11, the capacity of a pipe was the
        same as the system page size (e.g., 4096 bytes on i386).  Since
        Linux 2.6.11, the pipe capacity is 65536 bytes.

Bug 795617 - Implement opening and closing of LUKS mappings
2018-04-30 09:10:48 -06:00
Mike Fleetwood 9b52666bdb Simplify obtaining address of password memory for unit tests (#795617)
Use private access into the PasswordRAMStore class to directly obtain
the address of the locked memory, rather than inferring it from the
address of the first stored password.  This simplifies
PasswordRAMStoreTest::SetUpTestCase() and avoids encoding most of the
implementation knowledge that the first password will be stored at the
start of the protected memory.

Bug 795617 - Implement opening and closing of LUKS mappings
2018-04-30 09:10:48 -06:00
Mike Fleetwood d2a2ebe4a1 Add unit testing of erasing all passwords (#795617)
Test that all passwords are zeroed by PasswordRAMStore::erase_all(), the
same method as used in the PasswordRAMStore destructor.

Bug 795617 - Implement opening and closing of LUKS mappings
2018-04-30 09:10:48 -06:00
Mike Fleetwood 04637a3426 Add PasswordRAMStore module (#795617)
Application level requirements for secure password management were set
out in "LUKS password handling, threats and preventative measures" [1].

The requirements are:
1) Passwords are stored in RAM and are not allowed to be paged to swap.
   (However hibernating with GParted still running will write all of RAM
   to swap).
2) Passwords are wiped from RAM when no longer needed.  When each
   password is no longer needed and when GParted closes.
3) Passwords are referenced by unique key.  Recommend using LUKS UUIDs
   as the unique key.
   (Each LUKS password should only ever need to be entered once for each
   execution of GParted.  Therefore the passwords can't be stored in any
   of the existing data structures such as Partitions or LUKS_Info cache
   because all of these are cleared and reloaded on each device
   refresh).

There seems to be two possible implementation methods: use an existing
library to provide secure memory handling, or write our own.
Libgcrypt [2] and libsodium [3] cryptographic libraries both provide
secure memory handling.  (Secure memory is quite simple really, some
virtual memory locked into RAM which is zeroed when no longer needed).
Linking to an encryption library just to provide secure memory seems
like using a sledge hammer to crack a nut.  Also because of requirement
(3) above a module is needed to "own" the pointers to the passwords in
the secure memory.  Managing the secure memory ourselves is probably no
more code that that needed to interface to libgcrypt.  Therefore handle
the secure memory ourselves.

So far the module is only compiled.  It is not used anywhere in GParted.

[1] LUKS password handling, threats and preventative measures
    https://bugzilla.gnome.org/show_bug.cgi?id=627701#c56

[2] libgcrypt general purpose cryptographic library, as used in GNU
    Privacy Guard
    https://gnupg.org/related_software/libgcrypt/

[3] libsodium crypto library
    https://download.libsodium.org/doc/

Bug 795617 - Implement opening and closing of LUKS mappings
2018-04-30 09:10:48 -06:00
Mike Fleetwood 6c4ab5dc28 Remove checks for e4fsprogs commands (#794253)
PATCHSET OVERVIEW:

As of 31 March 2017 RHEL / CentOS 5 reached the end of their support
[1][2].  Therefore remove code which supports them.  This makes RHEL /
CentOS 6 the oldest supported distribution.  So the minimum required
versions of glibmm and gtkmm can be increased dropping some autoconf
checks and conditional code supporting older versions of these
libraries.  This will undo the bulk of these these previous bug fixes:

* GParted 0.21.0
  Bug 738706 - Add support for ext4 on RHEL/CentOS 5.x

* GParted 0.16.1
  Bug 695279 - Fix GParted doesn't compile on RHEL / CentOS 5.9

[1] Red Hat Enterprise Linux Life Cycle
    https://access.redhat.com/support/policy/updates/errata#Life_Cycle_Dates

[2] Subject: CentOS Linux 5 EOL
    https://lists.centos.org/pipermail/centos-announce/2017-April/022350.html

THIS PATCH:

Remove checks for e4fsprogs commands, removing support for ext4 on
RHEL / CentOS 5.x.  This is reverting earlier commit:
    f672f68863
    Check for e4fsprogs commands for ext4 support on RHEL/CentOS 5.x (#738706)

Mkfs_cmd member variable is being kept as a convenience so that it is
created once rather than on each use.  Also note that as it is a
Glib::ustring type object, it's constructor will be called which will
initialise it to the empty string so it doesn't need initialising to the
empty string in the initialiser list of the ext2() constructor itself.

Bug 794253 - Desupport RHEL / CentOS 5 and raise minimum required
             versions to glibmm 2.14.0 and gtkmm 2.16.0
2018-03-26 10:16:45 -06:00
Mike Fleetwood a3b47ca14a Move struct FS and FS_Limits into FileSystem.h
Struct FS and struct FS_Limits are strongly related to the FileSystem
class, both being return values from members and associated with storing
file system attributes.  Move their definitions from Utils.h into
FileSystem.h.
2018-01-28 10:09:35 -07:00
Mike Fleetwood 175d27c55d Rename enum FILESYSTEM to FSType
There are too many different types of things named "filesystem" in the
GParted code with the potential to cause confusion.  Namely:

    std::vector<FS> FILESYSTEMS
                              Vector of file system capabilities.

    class FileSystem          Base class interfacing to file system
                              specific executables for querying and
                              modification.

    enum FILESYSTEM           Symbolic constants representing each file
                              system type.

Many recent written or re-written functions already used a variable
named fstype.  Rename enum FILESYSTEM to enum FSType to clearly
distinguish it from the other things with very similar names.  Only
changing the name of the enumeration, not the name of variables of that
type too because that is a lot more lines of code and those can be
changed when the relevant code is re-written.
2018-01-28 10:09:35 -07:00
Mike Fleetwood 46bf5a383e Extract common code into GParted_Core::get_filesystem_limits() (#787204)
There are multiple repetitions of the same code getting a FileSystem
object, checking for NULL and then calling the file system specific
get_filesystem_limits().  Extract that into a common function.

GParted_Core::get_filesystem_limits() can't use the file system from the
passed Partition object because that is the current file system which
will be different from the intended file system for new and format
operations.  So would look up the wrong derived FileSystem specific
object and call the wrong get_filesystem_limits().  Hence still needing
fstype as a separate parameter to pass the intended file system.

Bug 787204 - Minimum and maximum size of the UDF partition/disk
2018-01-28 10:09:35 -07:00
Mike Fleetwood ae2a8723b5 Set dynamic UDF file system size limits (#787204)
UDF file system minimum and maximum size limits are defined in terms of
numbers of file system blocks.  So when resizing an existing file system
compute the byte size limits from the existing UDF file system's block
size.  Alternatively when creating a new UDF file system use the
device's sector size as the multiplier instead.

Bug 787204 - Minimum and maximum size of the UDF partition/disk
2018-01-28 10:09:35 -07:00
Mike Fleetwood 668957c0a4 Pass Partition object to get_filesystem_limits() (#787204)
As described in the previous commit, this is so that file system
specific implementations can dynamically determine size limits based on
Partition object attributes: such as the device sector size and the file
system block size.  (Assuming set_used_sectors() sets
partition.fs_block_size for the type of file system in question).

Bug 787204 - Minimum and maximum size of the UDF partition/disk
2018-01-28 10:09:35 -07:00
Mike Fleetwood e234df6b2e Remove struct FS members .MIN & .MAX (#787204)
All the code has been switched to call get_filesystem_limits() and use
struct FS_Limits.  Remove struct FS members .MIN & .MAX.

Bug 787204 - Minimum and maximum size of the UDF partition/disk
2018-01-28 10:09:35 -07:00
Mike Fleetwood 4fa262d7e3 Switch to using struct FS_Limits inside Dialog_Partition_New (#787204)
Change Dialog_Partition_New to use a fs_limits rather than struct FS
and .MIN and .MAX.  No passing of struct FS_Limits required.  Just use
the FILESYSTEMS vector of struct FS to provide the file system type and
look up it's size limits each time the selection changes.

Bug 787204 - Minimum and maximum size of the UDF partition/disk
2018-01-28 10:09:35 -07:00
Mike Fleetwood 53b7a75894 Query and pass struct FS_Limits into Dialog_Partition_Resize_Resize_Move (#787204)
Refactor Win_GParted::activate_resize() to query the file system size
limits using the new get_filesystem_limits() method and pass those
limits into the dialog class as struct FS_Limits.

Bug 787204 - Minimum and maximum size of the UDF partition/disk
2018-01-28 10:09:35 -07:00
Mike Fleetwood 285c24a82a Query and pass struct FS_Limits into Dialog_Partition_Copy (#787204)
Refactor Win_GParted::activate_paste() to query the file system size
limits using the new get_filesystem_limits() method and pass those
limits into the the dialog class as struct FS_Limits.

Bug 787204 - Minimum and maximum size of the UDF partition/disk
2018-01-28 10:09:35 -07:00
Mike Fleetwood fc436595fd Switch to using struct FS_Limits inside Dialog_Partition_Copy (#787204)
Adds working copy fs_limits member into common Dialog_Base_Partition
class.  Changes the internal code in Dialog_Partition_Copy class to use
fs_limits instead of fs.MIN and fs.MAX.  The limits are still passed
into the constructor via object of struct FS and it's members .MIN and
.MAX but immediately used to assign to the fs_limits member.

Bug 787204 - Minimum and maximum size of the UDF partition/disk
2018-01-28 10:09:35 -07:00
Mike Fleetwood 04535c48b3 Create separate file system limits structure and getter method (#787204)
PATCH SET OVERVIEW:

Currently the supported actions of each file system and their size
limits are stored in struct FS objects.  These are created by calling
file system specific derived implementations of
FileSystem::get_filesystem_support().  This happens when GParted is
started or when a when a rescan for supported actions is performed.  The
file system size limits are expressed as a fixed number of bytes.

The maximum UDF file system size is specified in terms of file system
block size units.  Also the file system block size must match the sector
size of the underlying device.  Typically 2K for optical media and 512
bytes or 4K for hard drives.

Therefore GParted can't properly express the true UDF file system size
limits because they depend on the block size of an existing UDF file
system or the sector size of the device for new UDF file systems.  In
fact other file systems such as EXT2/3/4 and XFS actually express their
maximum file system size in terms of numbers of file system blocks but
these tend to always be 4K and don't have to match the sector size of
the underlying device, so fixed byte values tend to suffice.

To update GParted for this, first separate file system size limits from
struct FS into struct FS_Limits and provide new
FileSystem::get_filesystem_limits() method to allow the limits to be
queried independently of the calls to get_filesystem_support().
Second, pass Partition objects and allow derived get_filesystem_limits()
implementations.

THIS PATCH:

Just creates a separate structure storing fixed value file system
minimum and maximum size limits along with getter method
get_filesystem_limits().

Bug 787204 - Minimum and maximum size of the UDF partition/disk
2018-01-28 10:09:35 -07:00
Pali Rohár 2f532be9f9 Use external tools udfinfo and udflabel for UDF file system (#792052)
Those external tools were introduced in version 2.0 of udftools package
and can show or change UDF label, UDF uuid and can provide information
needed for counting total/free sectors.

Bug 792052 - Add support for changing UDF label/uuid and show disk usage
2018-01-04 17:02:53 +00:00
Mike Fleetwood b04dbbc357 Rename function and reword text for rollback of failed file system move
To better reflect specifically that it is a failed (internally
implemented) file system move which is being rolled back.
2018-01-02 10:34:52 -07:00
Mike Fleetwood 0b5bf83b22 Enable failed partition change rollback for selected steps (#791875)
The general rule is that:
1) For a partition change step BEFORE a file system change step,
   rollback on failure;
2) For a partition change step AFTER a file system change step, don't
   rollback on failure.

Examining every case where resize_move_partition() is called and whether
rollback on failure is wanted or not:

* In resize_move()
    Resize / move extended partition.  No associated file system change.
  NO ROLLBACK
    Just to keep possibly applied operation.

* #1 in move()
    Making all encompassing partition before moving file system.
  ROLLBACK
    To restore partition boundaries back to those of the file system.

* #2 in move()
    Recreating original partition boundaries after file system move
    failed or was cancelled and has been rolled back.
  NO ROLLBACK
    To keep updated partition boundaries to match restored file system
    data.

* #3 in move()
    Replacing all encompassing partition with final partition after
    successful file system move.
  NO ROLLBACK
    Keep new partition boundaries to match moved file system.

* #1 in resize_encryption()
    Making the partition larger before growing closed LUKS encrypted
    data.
  ROLLBACK
    Restore partition boundaries back to those of the closed LUKS
    encrypted data.

* #2 in resize_encryption()
    Shrinking the partition after open LUKS mapping has been shrunk, but
    before swap is re-created (smaller).
  NO ROLLBACK
    Difficult case because the partition shrink is in the middle of a
    LUKS shrink and a swap shrink (re-create).  If swap was actually
    shrunk like other types of file system, rather than re-created, then
    the operation sequence would be (1) shrink swap, (2) shrink LUKS
    encryption, (3) shrink partition.  In this hypothetical case and the
    actual case no rollback is preferred to try to keep the new
    partition boundaries match the shrunk open LUKS encryption mapping.

* #3 in resize_encryption()
    Grow the partition before growing open LUKS mapping and re-creating
    swap larger.
  ROLLBACK
    Restore partition boundaries back to those of the smaller open LUKS
    encryption mapping.

* #4 in resize_encryption()
    Shrink the partition after shrinking the file system and open LUKS
    encryption mapping.
  NO ROLLBACK
    Keep new smaller partition boundaries to match shrunk encrypted file
    system.

* #5 in resize_encryption()
    Grow the partition before growing the open LUKS encryption mapping
    and file system.
  ROLLBACK
    Restore partition boundaries back to those of the not yet grown
    encrypted file system.

* #1 in resize_plain()
    Resize partition before re-creating swap a different size.
  ROLLBACK
    Restore partition boundaries back to those of the not yet resized
    (re-created) swap space.

* #2 in resize_plain()
    Shrink partition after shrinking the file system.
  NO ROLLBACK
    Keep new smaller partition boundaries to match shrunk file system.

* #3 in resize_plain()
    Grow partition before growing the file system.
  ROLLBACK
    Restore partition boundaries back to those of the not yet grown
    file system.

Removes the default value from the rollback_on_fail parameter so
rollback or not has to be explicitly specified for every call of
resize_move_partition().

Bug 791875 - Rollback specific failed partition change steps
2018-01-02 10:34:52 -07:00
Mike Fleetwood 0f16703bbb Implement rollback of failed partition resize/move steps (#791875)
Even after implementing a fix for bug 790418 "Unable to inform the
kernel of the change message may lead to corrupted partition table"
GParted/libparted can still encounter errors informing the kernel of the
new partition layout.  This has been seen with GParted on CentOS 7 with
libparted 3.1.

In such a case the partition has been successfully written to the disk
but just informing the kernel failed.  This is a problem because when a
partition is being moved in advance of a file system move step, failure
to inform the kernel leaves the partition boundaries not matching the on
disk limits of the file system.  For a move to the left this leaves the
partition reported as unknown, apparently losing the user's data.

For example start with a 512 MiB partition containing an XFS file
system.  This is recognised by blkid and parted, hence also by GParted.

    # blkid /dev/sdb1
    /dev/sdb1: UUID=... TYPE="xfs" PARTUUID="37965980-01"
    # parted /dev/sdb unit s print
    Model: ATA VBOX HARDDISK (scsi)
    Disk /dev/sdb: 16777216s
    Sector size (logical/physical): 512B/512B
    Partition Table: msdos
    Disk Flags:

    Number  Start     End       Size      Type     File system  Flags
     1      1048576s  2097151s  1048576s  primary  xfs

Now move the partition 100 MiB to the left and have it fail to inform
the kernel after the first partition change step.  Operation details:

    Move /dev/sdb1 to the left                                 (ERROR)
    * calibrate /dev/sdb1                                      (SUCCESS)
    * check file system on /dev/sdb1 for errors and (if poss...(SUCCESS)
    * grow partition from 512.00 MiB to 612.00 MiB             (ERROR)
        old start: 1048576
        old end: 2097151
        old size: 1048576 (512.00 MiB)
        requested start: 843776
        requested end: 2097151
        requested size: 1253376 (612.00 MiB)
      * libparted messages                                     (ERROR)
          Error informing the kernel about modifications to partition
          /dev/sdb1 -- Device or resource busy.  This means Linux won't
          know about any changes you made to /dev/sdb1 until you reboot
          -- so you shouldn't mount it or use it in any way before
          rebooting.  Failed to add partition 1 (resource temporarily
          unavailable)

Now because the start of the partition is 100 MiB before the start of
the file system, the file system is no longer recognised, and apparently
the user's data has been lost.

    # blkid /dev/sdb1
    /dev/sdb1: PARTUUID="37965980-01"
    # parted /dev/sdb unit s print
    ...
    Number  Start    End       Size      Type     File system  Flags
     1      843776s  2097151s  1253376s  primary

It doesn't matter why updating the partition failed, even if it was
because of an error writing to the disk.  Rollback of the change to the
partition should be attempted.  The worst case scenario is that rollback
of the change fails, which is the equivalent to how the code worked
before this patch set.

However in other cases where the partition boundaries are being updated
after a file system move or shrink step then the partition should be
updated to match the new location of the file system itself.  And no
rollback is wanted.  If the failure was only informing the kernel then
in fact the partition has actually been updated on disk after all.

So each partition resize/move step needs examining on a case by case
basis to decide if rolling back the change to the partition is wanted or
not.

This patch only adds partition change rollback into
resize_move_partition().  Rollback remains disabled until all cases are
examined in the following patch.

Bug 791875 - Rollback specific failed partition change steps
2018-01-02 10:34:52 -07:00
Mike Fleetwood 93ccc79e3a Extract common code into update_dmraid_entry() (#791875)
Extract common code which updates a DMRaid device mapper entry into a
sub-function.  This will also be needed when adding rollback of a
partition change on failure.

Bug 791875 - Rollback specific failed partition change steps
2018-01-02 10:34:52 -07:00
Mike Fleetwood 890d5a93a7 Extract code into resize_move_partition_implement() (#791875)
Extract the code which actually implements the partition change into a
sub-function ready for adding rollback of the change on failure.

Bug 791875 - Rollback specific failed partition change steps
2018-01-02 10:34:52 -07:00
Mike Fleetwood 8c5c13d613 Rename OperationDetailStatus STATUS_N_A to STATUS_WARNING
Make the enumeration name match it's use as indicating a warning.  Also
spell SUCCESS correctly.  Follow on to icon variable names too.
2017-11-26 10:53:52 -07:00
Mike Fleetwood 0688662055 Identify libparted messages as either success or error (#790842)
All libparted messages were reported as informational, even for a step
which failed.  Instead identify libparted messages as either
informational or errors depending on whether this step was successful
or not respectively.

Bug 790842 - Report libparted messages into operation details at the
             point at which they occur
2017-11-26 10:53:24 -07:00
Mike Fleetwood 23939331f6 Capture libparted messages via callback at top-level only (#790842)
Replace the explicit adding of libparted exception messages with a
callback to do it instead, and fire the callback just once per operation
by only changing the very top-level OperationDetail to use the new
set_success_and_capture_errors().  Therefore this still produces exactly
the same operation details with libparted messages at the end of each
operation.

Bug 790842 - Report libparted messages into operation details at the
             point at which they occur
2017-11-26 10:53:18 -07:00
Mike Fleetwood 2ed7feb2f5 Add mechanism to capture exception messages into an OperationDetail (#790842)
All code implementing a step of an operation follows this pattern:

    od.add_child(OperationDetail("Step heading"));
    od.get_last_child().add_child(OperationDetail("More details"));
    // Do step
    success = ...
    od.get_last_child().set_status(success ? STATUS_SUCCESS
                                           : STATUS_ERROR);

At this point any libparted messages reported via exceptions need to be
added into the OperationDetail tree.  Also adding further children into
the tree after collecting those errors needs to be prohibited (as much
as the previous patch prohibited it).

Add a new method which will replace the final set_status() call above
like this which set the status, captures the errors and flags that
further children shouldn't be added:

    ...
    od.get_last_child().set_success_and_capture_errors(status);

It emits a callback to capture the errors to provide flexibility and so
that the OperationDetail class doesn't have to get into the details of
how GParted_Core saves libparted exception messages.

Bug 790842 - Report libparted messages into operation details at the
             point at which they occur
2017-11-26 10:52:54 -07:00
Mike Fleetwood f8f9a72de6 Add mechanism to stop adding more child OperationDetails (#790842)
Want functionality to prevent further child details being added to an
OperationDetail.  This is so that the captured libparted error messages
are always the last child in the list, and more details (at that point
in the tree) can't be added.

For example we want GParted to report like this:

  Move /dev/sdb3 to the right and shrink it from 1.14 GiB to...(SUCCESS)
  ...
  * shrink partition from 1.14 GiB to 1.00 GiB                 (SUCCESS)
    * old start: 4464640
      old end: 6856703
      old size: 2392064 (1.14 GiB)
    * new start: 4464640
      new end: 6561791
      new size: 2097152 (1.00 GiB)
    * libparted messages                                       (INFO)
      * DEBUG: GParted generated synthetic libparted excepti...

and not like this:

  Move /dev/sdb3 to the right and shrink it from 1.14 GiB to...(SUCCESS)
  ...
  * shrink partition from 1.14 GiB to 1.00 GiB                 (SUCCESS)
    * old start: 4464640
      old end: 6856703
      old size: 2392064 (1.14 GiB)
    * libparted messages                                       (INFO)
      * DEBUG: GParted generated synthetic libparted excepti...
    * new start: 4464640
      new end: 6561791
      new size: 2097152 (1.00 GiB)

So actually preventing the addition of more child details would stop
users seeing information they should see.  So instead just report a bug
message into the operation details.  This doesn't stop anything, but the
bug message will be seen and allow us to fix GParted.

So far nothing is enforced.  This patch just adds the mechanism to
report a bug when a new child detail is added when prohibited.

Bug 790842 - Report libparted messages into operation details at the
             point at which they occur
2017-11-26 10:06:37 -07:00
Mike Fleetwood 33a535390e Extract common code into new method get_lp_partition() 2017-10-03 08:22:19 -06:00
Mike Fleetwood ea269cc929 Switch from whole_device flag to TYPE_UNPARTITIONED (#788308)
Remove whole_device flag and replace with new partition type
TYPE_UNPARTITIONED.  Minimally adapt the remaining code to compile and
run.

Bug 788308 - Remove whole_device partition flag
2017-10-03 08:22:19 -06:00
Mike Fleetwood c10d80a295 Add TYPE_UNPARTITIONED partition type (#788308)
Just adds the enumeration.  Using it will follow.

Bug 788308 - Remove whole_device partition flag
2017-10-03 08:22:19 -06:00
Mike Fleetwood 400864a65e Add and use Partition::set_unpartitioned() method (#788308)
PATCHSET OVERVIEW:

When unpartitioned drive read-write support was added this commit added
a whole_device flag:
   5098744f9a
   Add whole_device flag to the partition object (#743181)

Using a whole_device flags now seems not the correct way to model
unpartitioned drives.  GParted models an uninitialised drive as:
    .path         = _("uninitialized")
    .type         = TYPE_UNALLOCATED
    .whole_device = true
    .filesystem   = FS_UNALLOCATED
and a whole drive file system, using ext4 for example, as:
    .path         = "/dev/sdb"
    .type         = TYPE_PRIMARY
    .whole_device = true
    .filesystem   = FS_EXT4
No partitioning changed yet the type of the partition in the model
changed between TYPE_UNALLOCATED and TYPE_PRIMARY depending on whether
the whole drive contains a recognised file system or not.

The partition object describing a file system within a LUKS encryption
mapping is another case of the model not matching reality.
    .path         = /dev/mapper/crypt_sdb1_crypt
    .type         = TYPE_PRIMARY
    .whole_device = true
    .filesystem   = FS_EXT4
There is no partition table within the encryption mapping, the file
system fills it, but GParted records it as a primary partition.

Make TYPE_UNALLOCATED and TYPE_PRIMARY be reserved for representing
unallocated space and primary partitions within a partitioned disk drive
and introduce new TYPE_UNPARTITIONED for all cases of an unpartitioned
whole disk drive.

The GParted UI does differentiate between an unallocated whole disk
device and anything else by requiring a partition table to be created
first, even if that is just the loop partition table.  That
determination can simply look for the partition object containing file
system type FS_UNALLOCATED instead.

THIS PATCH:

Create set_unpartitioned() helper method to set a partition object to
represent a whole disk drive and use everywhere such an object is
modelled.  This matches what existing methods Set_Unallocated() and
indeed Set() do for unallocated space and any type of partition
respectively.

For now the partition type is still set to either TYPE_UNALLOCATED or
TYPE_PRIMARY so the rest of the code base remains the same.
TYPE_UNPARTITIONED will be introduced later.

Bug 788308 - Remove whole_device partition flag
2017-10-03 08:22:06 -06:00
Pali Rohár e8f0504b13 Make sure that FS_Info cache is loaded for all named paths (#787181)
Naming a file system image file on the command line is shown by GParted
as unknown.

    $ truncate -s 100M /tmp/fat.img
    $ mkfs.vfat /tmp/fat.img
    $ sudo ./gpartedbin /tmp/fat.img

Currently the FS_Info cache is loaded for all devices reported by
blkid (plus all whole disk devices identified from /proc/partitions even
if blkid reports nothing).  However file system images named on the
command line are not queried so GParted can't identify them.

Fix by ensuring that the FS_Info blkid cache is loaded for all named
devices, including named file system image files.

Note that Mount_Info::load_cache() depends on the contents of the
FS_Info cache to lookup UUID= and LABEL= device names from /etc/fstab.
However only file systems in block devices can be mounted like this, and
never file system image files, so the fact that the cache may be
extended afterwards by FS_Info::load_cache_for_paths() does not matter.

History

Prior to version 0.22.0, when unpartitioned drive support was added,
GParted could recognise some file system image files using loop
partition handling in libparted.  However libparted before version 3.2
reported the loop partition name as the whole disk device name appended
with "1" so all the query commands were provided a non-existent name to
use.  Therefore no file system usage or the label was displayed.

Bug 787181 - Fix detection of file system images
2017-09-12 19:10:20 +01:00
Mike Fleetwood 73fe1dbf5c Support /etc/fstab using Unicode labels as mount points (#786502)
So far GParted is still loading the default non-reversible encoded
labels from blkid in the initial loading of the FS_Info module cache.
This encoded label is used to match LABEL=<label> when reading
/etc/fstab, via the get_path_by_label() call, so works for ASCII only
labels.  This prevents GParted enabling the "mount on >" partition menu
item when non-ASCII labels are used.

To fix this:
1) Stop reading the labels the wrong way.
   Via the blkid command used to initially load the FS_Info module cache
   and is subject to default non-reversible encoding of non-printable
   ASCII bytes.
2) Read all the labels the right way, but only when needed.
   Only when /etc/fstab file contains LABEL=<label> and
   get_path_by_label() is called, read all the labels from blkid without
   encoding them via run_blkid_update_cache_one_label().
3) Return label from the cache.
   get_label() returns the cached label, loading it into the cache first
   if needed with run_blkid_update_cache_one_label().

In the worst case scenario of having a LABEL=<label> in /etc/fstab blkid
will be run for every partition containing a recognised file system to
read the label.  On my desktop with 5 hard drives, 4  SWRaid arrays and
31 recognised file systems running 'blkid -o value -s LABEL ...' 31
times took 0.074 seconds of a total scan time of 9.072 seconds.  Less
that 1% of the total scanning time.  When LABEL=<label> is not used in
/etc/fstab individual blkid executions are only used to read labels for
file systems where there is no file system specific tool available
reducing the impact further.  Blkid itself caches the data in it's
blkid.tab cache file rather than reading all file systems on each
invocation.  Also the Linux file system cache will already contain the
blkid executable file, needed libraries files and the blkid.tab cache
file itself.  Hence why repeated execution of blkid is so fast.

Further to the updated comment in set_partition_label_and_uuid().
Matching LABEL=<label> from /etc/fstab uses the label obtained from
blkid run in the C locale so this kind of assumes it returns the label
correctly and it does for my limited testing on Unicode enabled
desktops.  Just not sure if it would be true for all cases in all
locales compared to the FS specific command run in the users default
locale.

Bug 786502 - Support reading Unicode labels when file system specific
             tools aren't available
2017-09-02 13:25:26 -06:00
Mike Fleetwood b022c1e3a9 Update FS_Info cache with Unicode safe labels read from blkid (#786502)
Move the code which reads the Unicode label from FS_Info::get_label()
into new function run_blkid_update_cache_one_label() which also replaces
the non-reversibly encoded copy loaded during the initial cache load.

This is mainly a bit of code refactoring ready for the following change.
It deliberately keeps the initial loaded labels so that reading
/etc/fstab and decoding LABEL=<label> to block special device names via
FS_Info::get_path_by_label() continues to works, at least for ASCII only
labels.

Bug 786502 - Support reading Unicode labels when file system specific
             tools aren't available
2017-09-02 13:25:26 -06:00
Mike Fleetwood a0c44d766d Refactor UDF label manipulation code (#784533)
Make especially the Volume Identifier length limit code simpler to
understand and therefore easier to maintain.

Bug 784533 - Add support for UDF file system
2017-07-30 09:50:09 +01:00
Pali Rohár 861bc8df5d Add support for long UDF labels and check for old versions of mkudffs (#784533)
UDF label is stored in the Logical Volume Identifier which has space for
either 126 Latin1 or 63 UCS-2 characters.  For compatibility reasons
with older versions of blkid, the possibly truncated UDF label is also
stored in the Volume Identifier which only has space for 30 Latin1 or 15
UCS-2 characters.

Because versions of mkudffs prior to 1.1 damage the label if it contains
non-ASCII characters, make sure GParted does not call such versions of
mkudffs with a non-ASCII character label.

Bug 784533 - Add support for UDF file system
2017-07-30 09:50:09 +01:00
Pali Rohár 5f327feb25 Add support for UDF file system (#784533)
Add support for detecting UDF file systems and formatting hard disks
with revision 2.01 UDF file systems using udftools.  Formatting optical
disks or any other media types is not supported yet.  Changing label or
UUID after formatting is not supported as the tools do not yet exist.

Bug 784533 - Add support for UDF file system
2017-07-10 19:17:05 +01:00
Mike Fleetwood 25780c611b Further improve speed of PipeCapture for non-watched output (#777973)
For large output a lot of time is used copying capturebuf to callerbuf
to provide a Glib::ustring copy of the buffer for the update callback.
However update callbacks are only used when commands are run to apply
operations by FileSystem::execute_command() and their output is
incrementally displayed in the UI.  Whereas update callbacks are never
used when commands are used to query information via
Utils::execute_command().

Stop performing interim copying of capturebuf to callerbuf when there
are no update callbacks registered as it is unnecessary.

Time to read portions of the recorded fsck.fat output via
fat16::set_used_sectors() and intermediate copies aren't required:

                     1 MiB     10 MiB   122 MiB
    old code :   0.074 sec   1.41 sec   210 sec [3:30]
    new code :   0.063 sec   0.56 sec     6.57 sec

Bug 777973 - Segmentation fault on bad disk
2017-06-02 11:47:35 -06:00
Mike Fleetwood 8dbbb47ce2 Workaround g_utf8_get_char_validate() bug with embedded NUL bytes (#777973)
If PipeCapture reads a NUL byte in the middle of what is expected to be
a multi-byte UTF-8 character then PipeCapture either returns the
captured characters to the previous update or loops forever depending on
whether the end of the stream is encountered before the read buffer is
full or not.  This is equivalent to saying whether the NUL byte occurs
within the last 512 bytes of the output or not.

This is caused by a bug in g_utf8_get_char_validated() reporting that a
partial UTF-8 character has been found when the NUL byte is encountered
in the middle of a multi-byte character even though more bytes are
available in the length specified buffer.  g_utf8_get_char_validated()
is always stopping at the NUL byte assuming it is working with a NUL
terminated string.

Workaround this by checking for g_utf8_get_char_validated() claiming a
partial UTF-8 character has been found when in fact there are at least
enough bytes in the read buffer to instead determine that it is really
an invalid UTF-8 character.

Reference:
    Bug 780095 - g_utf8_get_char_validated() stopping at nul byte even
                 for length specified buffers
    https://bugzilla.gnome.org/show_bug.cgi?id=780095

Bug 777973 - Segmentation fault on bad disk
2017-06-02 11:47:35 -06:00
Mike Fleetwood b5b3d199f8 Improve the performance of PipeCapture for large output (#777973)
A user had a very corrupted FAT file system such that fsck.fat produced
122 MiB of output.  GParted has to read this output to get the file
system usage information.  However GParted takes more than 48 hours to
read the 122 MiB of output, while using 100% CPU time and is
unresponsive for the duration.

Modified fsck.fat to output just the first 1 MiB of output and used perf
to capture performance data from GParted reading that output:
    # perf -g -F 1999 -- ./gpartedbin
    # perf report --stdio
      67.84% Glib::ustring::replace      [4.23s]
      17.67% g_utf8_pointer_to_offset    [1.10s]
       8.48% g_utf8_offset_to_pointer    [0.53s]
    [  6.01% (everything else)       ]   [0.38s]
    [100.00% TOTAL                   ]   [6.24s]

And to read the first 10 MiB of output the performance figures are:
      92.95% Glib::ustring::replace      [257.44s]
       4.35% g_utf8_pointer_to_offset    [ 12.05s]
       2.13% g_utf8_offset_to_pointer    [  5.90s]
    [  0.58% (everything else)       ]   [  1.61s]
    [100.00% TOTAL                   ]   [277.00s]

See how the total time is increasing non-linearly, 44 times longer for
only 10 times as much data.  This is because of the exponential increase
in time spent in Glib::ustring::replace.

After a lot of experimentation I came to the conclusion that
Glib::ustrings are not appropriate for storing and editing large buffers
of data, sizes megabytes and above.  The issues are that iterators are
invalid after the content changes and replacing UTF-8 characters by
index gets exponentially slower as the size of the string increases.
Hence the > 48 hours of 100% CPU time to read and apply the line
discipline to the 122 MiB of fsck.fat output.  See code comment for a
more detailed description of the issues found.

Rewrote OnReadable() to use Glib::ustrings as little as possible.
Instead using buffers and vectors of fixed width data types allowing for
fast access using pointers and indexes (converted to pointers by the
compiler with simple arithmetic).  Again see code comment for a more
detailed description of the implementation.

Repeating the performance capture with the new code for the first 1 MiB
of fsck.fat output:
      63.34% memcpy                      [0.35s]
    [ 36.66% (everything else)       ]   [0.21s]
    [100.00% TOTAL                   ]   [0.56s]

And for the first 10 MiB of fsck.fat output:
      96.66% memcpy                      [63.60s]
    [  3.34% (everything else)       ]   [ 2.20s]
    [100.00% TOTAL                   ]   [65.80s]

Simple timings taken to read portions of the fsck.fat output (when not
using perf):

                   1 MiB    10 MiB      122 MiB
    old code :   6.2 sec   277 sec   > 48 hours
                            (4:37)
    new code :   0.6 sec    66 sec    17262 sec
                            (1:06)    (4:47:42)

Performance of the code is still non-linear because of the assignment
of the ever growing capturebuf to callerbuf for every block of input
read.  This is required to generate a consistent Glib::ustring copy of
the input for the update callback.  However this is much faster than
before, and I have a plan for further improvements.

Bug 777973 - Segmentation fault on bad disk
2017-06-02 11:47:35 -06:00
Mike Fleetwood 69d1bbcf8f Remove old .cvsignore files
As the source code is managed in GIT and there is a .gitignore file in
the top level directory specifying file names to exclude from version
control, then the old per-directory .cvsignore files for CVS are
redundant.

Add the only missing and applicable entry from src/.cvsignore of '.libs'
to .gitignore and remove all the .cvsignore files.
2017-06-02 10:47:35 -06:00
Mike Fleetwood 75131d85a5 Fix snap-to-alignment of operations creating partitions (#779339)
Using the default MiB alignment, creating an MSDOS logical partition
between two other existing logical partitions fails with this error
dialog:

    (-) <b>An error occurred while applying the operations</b>
        See the details for more information.
        <b>IMPORTANT</b>
        If you want support, you need to provide the saved details!
        See http://gparted.org/save-details.htm for more information.
                                                               [ OK ]

and these operation details:

    + libparted messages
      - Unable to satisfy all constraints on the partition.

This bug was introduced by this commit included in GParted 0.23.0:
    90e3ed68fc
    Shallow copy Device object into Operation object (#750168)

The commit message claimed that the deep copied Partition objects inside
the Device inside the Operation object are never accessed.  This turned
out not to be true.  Win_GParted::Add_Operation() uses them as part of
snap_to_alignment() which updates requested partition boundaries to
account for alignment requirements and the space needed for EBR
(Extended Boot Record) preceding logical partitions.

In this case the new logical partition was trying to be created over the
top of the EBR for the following logical partition because
snap_to_alignment() wasn't aware of its existence.

Fix by making Add_Operation() and snap_to_alignment() refer to the
current device, as displayed in the UI, rather than the shallow copy
included in the Operation object.  Hopefully now it is true that the
not copied vector of Partition objects in the Device object in each
Operation object are never accessed.

Bug 779339 - enforce at least 1 MiB "free space following"
2017-04-23 08:57:25 -06:00
Mike Fleetwood aa98107706 Create and use general find_extended_partition() function
The Operation class already provided find_index_extended() method and
 was used in the Operation and derived classes where required.  It
returns the index to the extended partition in the PartitionVector
object, or -1 when no extended partition exists.

There were several cases of the same functionality being open coded in
GParted_Core and Win_GParted.  Therefore move the implementation to
find_extended_partition() in PartitionVector compilation unit and use
this implementation everywhere.
2017-01-14 08:49:58 -07:00
Mike Fleetwood 786a53b43c Replace 2 Win_GParted member variables with local variables
Member variables fs and gpart_output were used in just one method each
as local variables.  Replace them with local variables.
2017-01-14 08:49:58 -07:00
Mike Fleetwood 0f76b8f8ff Remove unused clear_mountpoints parameter from add_mountpoint*()
The clear_mountpoints parameter has never been used since
add_mountpoint*() were first added [1][2].  clear_mountpoints() method
[3] is available to provide this functionality and used.  Therefore
removed unused parameter and code.

[1] add_mountpoints() added 2006-03-15
        9532c3cad1
        Made Partition::mountpoints private

[2] add_mountpoint() added 2011-12-16
        208083f11d84dbd4f186271a3cdbf5170db259f8b8
        Display LVM2 VGNAME as the PV's mount point (#160787)

[3] clear_mountpoint() added 2006-03-19
        ad9f2126e7
        fixed issues with copying (see also #335004) cleanups + added FIXME added
2017-01-14 08:49:58 -07:00
Mike Fleetwood 36804b9634 Implement maximize encryption volume as part of check repair operation (#774818)
Now that resizing of encrypted file systems is implemented add growing
of the open LUKS mapping as part of the check repair operation.

Resizing an encrypted file system requires the LUKS mapping to be open
to access the file system within; therefore it also requires libparted
and kernel support for online partition resizing.  This limits resizing
to the latest distributions with libparted >= 3.2 and kernel >= 3.6.
However growing an open LUKS mapping as part of a check repair operation
doesn't require resizing the partition.  Therefore route via offline
grow of LUKS to avoid those extra, unnecessary requirement.  This does
mean that offline LUKS grow artificially requires cryptsetup, but that is
not really significant as even opening LUKS requires cryptsetup.

So now checking an encrypted file system on even the oldest
distributions does:
1) runs FSCK on the encrypted file system;
2) grows the encryption volume to fill the partition;
3) grows the file system to fill the encryption mapping.

Bug 774818 - Implement LUKS read-write actions NOT requiring a
             passphrase
2017-01-14 08:49:58 -07:00
Mike Fleetwood 828f0d8ab3 Implement resize/move operation of encrypted file systems (#774818)
Moving of closed LUKS is simply enabled by luks .move capability being
set and requires no further coding.

Resizing of encrypted file systems requires both the LUKS mapping and
encrypted file system within to be resized in the right order for both
shrinking and growing.  To keep the code simple split resizing of plain
and encrypted into separate functions.

Bug 774818 - Implement LUKS read-write actions NOT requiring a
             passphrase
2017-01-14 08:49:58 -07:00
Mike Fleetwood ee1b2257d2 Preview resize/move operation of encrypted file systems (#774818)
Changing the Resize/Move dialog code to also handle PartitionLUKS
objects was considered too complicated.  Instead create an unencrypted
equivalent using clone_as_plain(), pass that to the Resize/Move dialog
and finally apply the change back using Partition*::resize().

Bug 774818 - Implement LUKS read-write actions NOT requiring a
             passphrase
2017-01-14 08:49:58 -07:00
Mike Fleetwood 08e4ba4eca Add Partition object resizing method Partition*::resize() (#774818)
Add a resize() method to both Partition and PartitionLUKS classes.  They
take a reference Partition object, and update the position, size and
file system usage of *this Partition to match.  This is ready for taking
a partition returned from Resize/Move dialog and applying the change.

Bug 774818 - Implement LUKS read-write actions NOT requiring a
             passphrase
2017-01-14 08:49:58 -07:00
Mike Fleetwood 30a0f4506c Add specialist clone method PartitionLUKS::clone_as_plain() (#774818)
Implement a specialist PartitionLUKS clone method.  Creates a new
Partition object which has the same space usage as the source encrypted
file system, but is a plain file system.  Namely, the overhead of the
LUKS header has been added to the file system usage.  This is ready for
feeding this representation of the partition to the Resize/Move dialog.

Bug 774818 - Implement LUKS read-write actions NOT requiring a
             passphrase
2017-01-14 08:49:58 -07:00
Mike Fleetwood 88136c96d7 Extend functions generating encrypted file system string (#774818)
Already have:
    Utils::get_filesystem_string(FS_EXT2)          -> "ext2"
    virtual Partition::get_filesystem_string()     -> "ext2"
    virtual PartitionLUKS::get_filesystem_string() -> "[Encrypted] ext2"
Add these:
    Utils::get_encrypted_string()                  -> "[Encrypted]"
    Utils::get_filesystem_string(false, FS_EXT2)   -> "ext2"
    Utils::get_filesystem_string(true, FS_EXT2)    -> "[Encrypted] ext2"

This is ready for use of Utils::get_filesystem_string(true, FS_EXT2)
when composing the preview of a format of an encrypted file system by
Win_GParted::activate_format().

Bug 774818 - Implement LUKS read-write actions NOT requiring a
             passphrase
2017-01-14 08:49:58 -07:00
Mike Fleetwood 3ba7128d55 Implement new UUID operation on encrypted file systems (#774818)
When composing, describing and implementing the operation just need the
code to query and set the Partition object directly containing the file
system, instead of the enclosing encryption mapping to make it work.

The operation details for setting a new UUID on an encrypted ext4 file
system become:

    Set a new random UUID on [Encrypted] ext4 file system on /dev/sdb4
    + calibrate /dev/sdb4
    + Set UUID on /dev/mapper/sdb4_crypt to a new, random value
      + tune2fs -U random /dev/mapper/sdb4_crypt
          tune2fs 1.41.12 (17-May-2010)

Also note the now documented rule in apply_operation_to_disk() which
says each operation must leave the status of the encryption mapping and
file system as it found it.

Bug 774818 - Implement LUKS read-write actions NOT requiring a
             passphrase
2017-01-14 08:49:58 -07:00
Mike Fleetwood bd6fc67afb Provide virtual Partition::get_filesystem_string() method (#774818)
Provide and use a single interface for getting the file system string
for display, regardless of whether the partition is encrypted or the
encryption mapping is active or not.

Example return values for get_filesystem_string() for different types
and states of Partition objects:
1)  Plain ext4 file system:          -> "ext4"
2)  Closed encrypted:                -> "[Encrypted]"
3)  Open encrypted ext4 file system: -> "[Encrypted] ext4"

This simplifies the code in TreeView_Detail::create_row() which sets the
file system type displayed in the main window.  The same method will
then also be used when setting the operation description as each
operation is updated to handle encrypted file systems.

Bug 774818 - Implement LUKS read-write actions NOT requiring a
             passphrase
2017-01-14 08:49:58 -07:00
Mike Fleetwood aa49b763e4 Remove virtual PartitionLUKS::get_filesystem_label() (#774818)
The previous commit changed how the code behind the main window
retrieved the file system label for display.  This is the relevant
changes in TreeView_Detail::create_row():

  + const Partition & filesystem_ptn = partition.get_filesystem_partition();
    ...
  - Glib::ustring temp_filesystem_label = partition.get_filesystem_label();
  + Glib::ustring temp_filesystem_label = filesystem_ptn.get_filesystem_label();
    treerow[treeview_detail_columns.label] = temp_filesystem_label;

In the case of an encrypted file system get_filesystem_label() is now
called on the Partition object directly rather than on the outer
Partition object containing the LUKS encryption.

The code behind the Information dialog always obtained and used the
Partition object directly containing the file system to call
get_filesystem_label() since read-only LUKS support was added.
Therefore the virtualised PartitionLUKS::get_filesystem_label() is no
longer needed, so remove it.

Bug 774818 - Implement LUKS read-write actions NOT requiring a
             passphrase
2017-01-14 08:49:58 -07:00
Mike Fleetwood 53fd80e6ca Provide virtual Partition::get_filesystem_partition() method (#774818)
There are multiple cases of code wanting to work with the Partition
object directly containing the file system, regardless of whether it is
within a PartitionLUKS object or not.  The code had to do something
similar to this to access it:

    const Partition * filesystem_ptn = &partition;
    if ( partition.filesystem == FS_LUKS && partition.busy )
            filesystem_ptn = &dynamic_cast<const PartitionLUKS *>( &partition )->get_encrypted();
    ...
    // Access Partition object directly containing the file system
    filesystem_ptn-> ...

Implement and use virtual accessor get_filesystem_partition() which
allows the code to be simplified like this:

    const Partition & filesystem_ptn = partition.get_filesystem_partition();
    ...
    // Access Partition object directly containing the file system
    filesystem_ptn. ...

Bug 774818 - Implement LUKS read-write actions NOT requiring a
             passphrase
2017-01-14 08:49:58 -07:00
Mike Fleetwood b2190372d0 Ensure blkid FS_Info cache has entries for all whole disk devices (#771244)
More recent versions of blkid don't report an ISO9660 file system on the
whole disk device if partitions can be reports for embedded partitions.
However when querying the whole disk device directly then the expected
ISO9660 file system is reported.  For example on CentOS 7 with the
previous ISO images:

    # wget http://git.kernel.org/cgit/utils/util-linux/util-linux.git/plain/tests/ts/isosize/sample.iso.gz
    # dd if=/dev/zero bs=1M of=/dev/sdc
    # zcat sample.iso.gz | dd of=/dev/sdc

    # blkid -v
    blkid from util-linux 2.23.2  (libblkid 2.23.0, 25-Apr-2013)
    # blkid | fgrep /dev/sdc
    /dev/sdc1: UUID="2013-01-04-22-05-45-00" LABEL="ARCH_201301" TYPE="iso9660" PTTYPE="dos"
    # blkid /dev/sdc
    /dev/sdc: UUID="2013-01-04-22-05-45-00" LABEL="ARCH_201301" TYPE="iso9660" PTTYPE="dos"

    # wget http://cdimage.debian.org/debian-cd/8.6.0/amd64/iso-cd/debian-8.6.0-amd64-netinst.iso
    # dd if=/dev/zero bs=1M of=/dev/sdc
    # dd if=debian-8.6.0-amd64-netinst.iso bs=1M of=/dev/sdc

    # blkid | fgrep /dev/sdc
    /dev/sdc1: UUID="2016-09-17-14-23-48-00" LABEL="Debian 8.6.0 amd64 1" TYPE="iso9660" PTTYPE="dos"
    /dev/sdc2: SEC_TYPE="msdos" UUID="17F3-1162" TYPE="vfat"
    # blkid /dev/sdc
    /dev/sdc: UUID="2016-09-17-14-23-48-00" LABEL="Debian 8.6.0 amd64 1" TYPE="iso9660" PTTYPE="dos"

This behavioural difference with blkid is probably as a result of newer
versions of udev informing the kernel of the partitions embedded within
the ISO9660 image, and not directly as a result of a change in blkid
itself.  Older distributions don't have partition entries for the above
ISO images, but CentOS 7 (with udev 219) and later distributions do have
partition entries:

    # fgrep sdc /proc/partitions
       8       16    8388608 sdc
       8       17     252928 sdc1
       8       18        416 sdc2

Fix by ensuring that the blkid FS_Info cache has entries for whole disk
devices, even if each entry has all empty attributes because there is a
partition table and not a recognised file system.

Calling blkid on whole disk devices containing partition tables produces
output like this, with newer versions of blkid:

    # blkid /dev/sda
    /dev/sda: PTTYPE="dos"
    # blkid /dev/sdb
    /dev/sdb: PTTYPE="gpt"

This will be loaded into the FS_Info cache as a blank entry for the
device by run_blkid_load_cache().  There will be a path name but all the
other attributes will be blank because there are no TYPE, SEC_TYPE, UUID
or LABEL name value pairs.  With older versions of blkid no output is
produced at all.  In that case load_fs_info_cache_extra_for_path() will
create the same blank entry with just the path name defined.

Bug 771244 - gparted does not recognize the iso9660 file system in
             cloned Ubuntu USB boot drives
2017-01-06 12:21:50 -07:00
Mike Fleetwood fd426cf36e Create new method GParted_Core::set_device_from_disk() (#771244)
Move code from GParted_Core::set_devices_thread() performing top level
population of each Device object during the scan of the drives into new
set_device_from_disk() method.

Bug 771244 - gparted does not recognize the iso9660 file system in
             cloned Ubuntu USB boot drives
2017-01-06 10:47:11 -07:00
Curtis Gedak f762c0cc34 Add detection of iso9660 file system (#771244)
Requires blkid.

Note that FS_LUKS was also moved to more closely match the order in
include/Utils.h

Bug 771244 - gparted does not recognize the iso9660 file system in
             cloned Ubuntu USB boot drives
2017-01-06 10:47:11 -07:00
Mike Fleetwood 029a8eb19d Stop providing a default for FileSystem::resize() fill_partition argument
FileSystem::resize() (and derived) is only ever called from a single
location and always with the fill_partition argument supplied [1].
Therefore providing a default for the argument is unnecessary.  So
remove it.

[1] Since these two commits from 2006-06-17, before GParted 0.3.0, which
    added resize_filesystem() and maximize_filesystem() methods to wrap
    calls to p_filesystem->resize() into a single location:

    08245cd08c
    cleanups in the core and the fs'es (resize)

    2d7fb5700b
    more cleanups in the core and the fs'es (these changelogs are getting
2016-12-12 13:15:34 -07:00
Mike Fleetwood 8979913a3f Remove "../include/" from GParted header #includes
It made the code look a little messy, is easily resolved in the build
system and made the dependencies more complicated than needed.  Each
GParted header was tracked via multiple different names (different
numbers of "../include/" prefixes).  For example just looking at how
DialogFeatures.o depends on Utils.h:

    $ cd src
    $ make DialogFeatures.o
    $ egrep ' [^ ]*Utils.h' .deps/DialogFeatures.Po
     ../include/DialogFeatures.h ../include/../include/Utils.h \
     ../include/../include/../include/../include/../include/../include/Utils.h \
     ../include/../include/../include/Utils.h \

After removing "../include/" from the GParted header #includes, just
need to add "-I../include" to the compile command via the AM_CPPFLAGS in
src/Makefile.am.  Now the dependencies on GParted header files are
tracked under a single name (with a single "../include/" prefix).  Now
DialogFeatures.o only depends on a single name to Utils.h:

    $ make DialogFeatures.o
    $ egrep ' [^ ]*Utils.h' .deps/DialogFeatures.Po
     ../include/DialogFeatures.h ../include/Utils.h ../include/i18n.h \
2016-12-12 13:15:34 -07:00
Mike Fleetwood 2740113dcb Refactor linux-swap recreation (#775932)
Linux-swap is recreated as part of copy, resize and move operations and
the code was special cased to implement that by calling the linux-swap
specific resize method.  However the displayed text always said "growing
file system" and then proceeded to recreate linux swap.  Example
operation:

    Copy /dev/sdb1 to /dev/sdb2
    ...
    + copy file system from /dev/sdb1 to /dev/sdb2
        Partition copy action skipped because linux-swap file system does not contain data
    + grow file system to fill the partition
      + create new linux-swap file system
        + mkswap -L"" -U "77d939ef-54d6-427a-a2bf-a053da7eed4c" /dev/sdb2
            Setting up swapspace version 1, size = 262140 KiB
            LABEL=, UUID=77d939ef-54d6-427a-a2bf-a053da7eed4c

Fix by writing recreate_linux_swap_filesystem() method with better
messaging and use everywhere maximise_filesystem() was previously used
to recreate linux-swap.  Also as this is a create step, erase the
partition first to prevent the possibility of any other file system
signatures being found afterwards.  Now the operation steps are more
reflective of what is actually being performed.

    Copy /dev/sdb1 to /dev/sdb2
    ...
    + copy file system from /dev/sdb1 to /dev/sdb2
        Partition copy action skipped because linux-swap file system does not contain data
    + clear old file system signatures in /dev/sdb2
    + create new linux-swap file system
      + mkswap -L"" -U "77d939ef-54d6-427a-a2bf-a053da7eed4c" /dev/sdb2
          Setting up swapspace version 1, size = 262140 KiB
          LABEL=, UUID=77d939ef-54d6-427a-a2bf-a053da7eed4c

Bug 775932 - Refactor mostly applying of operations
2016-12-12 13:15:34 -07:00
Mike Fleetwood a0158abbeb Refactor resizing file system apply methods (#775932)
resize_filesystem() was meeting two different needs:
1) when called with fill_partition = false it generated operation
   details;
2) when called from maximize_filesystem() with fill_partition = true it
   skipped generating any operation details;
then ran the switch statement to select the resize implementation.  So
extract the common switch statement into new method
resize_filesystem_implement().

Then observe that the only time resize_filesystem() was called to grow
the file system was when re-creating linux-swap.  Therefore change that
call to use maximize_filesystem() and rename to shrink_filesystem() and
modify the operation detail messages to match.

Bug 775932 - Refactor mostly applying of operations
2016-12-12 13:15:34 -07:00
Mike Fleetwood 0420159c1d Rename a few GParted_Core apply related methods (#775932)
Make the methods called below apply_operation_to_disk() follow a
standard naming convention:

 *  Contains "_partition"
    Uses libparted to query or change the partition in the disk label
    (partition table).
    E.g.:
        calibrate_partition()
        create_partition()
        delete_partition()
        name_partition()
        resize_move_partition()
        set_partition_type()

 *  Contains "_filesystem"
    Manipulates the file system within the partition, mostly using the
    FileSystem and derived class methods.
    E.g.:
        create_filesystem()
        remove_filesystem()
        label_filesystem()
        copy_filesystem()
        erase_filesystem_signatures()
        check_repair_filesystem()
        resize_filesystem()
        maximize_filesystem()

 *  Other
    Compound method calling multiple partition and file system related
    apply methods.
    E.g.:
        create()
        format()
        copy()
        resize_move()
        resize()
        move()

Rename:
    Delete()      -> delete_partition()
    change_uuid() -> change_filesystem_uuid()

Bug 775932 - Refactor mostly applying of operations
2016-12-12 13:15:34 -07:00
Mike Fleetwood 9f08875997 Make encrypted Partition objects look like whole disk device ones (#775932)
Until now an encryption mapping has been modelled as a Partition object
similar to a partition like this:
    .encrypted.device_path  = "/dev/sdb1"
    .encrypted.path         = "/dev/mapper/sdb1_crypt"
    .encrypted.whole_device = false
    .encrypted.sector_start = // start of the mapping in the partition
    .encrypted.sector_end   = // end of the mapping in the partition
However accessing device_path in the start to end sector range is not
equivalent to accessing the partition path as it doesn't provide access
to the encrypted data.  Therefore existing functions which read and
write partition data (GParted file system copying and signature erasure)
via libparted using the device_path won't work and will in fact destroy
the encrypted data.  This could be coded around with an extra case in
the device opening code, however it is not necessary.

An encrypted block special device /dev/mapper/CRYPTNAME looks just like
a whole disk device because it doesn't contain a partition and the file
system it contains starts at sector 0 and goes to the end.  Therefore
model an encryption mapping in the same way a whole disk device is
modelled as a Partition object like this:
    .encrypted.device_path  = "/dev/mapper/sdb1_crypt"
    .encrypted.path         = "/dev/mapper/sdb1_crypt"
    .encrypted.whole_device = true
    .encrypted.sector_start = 0
    .encrypted.sector_end   = // size of the encryption mapping - 1
Now GParted file system copy and erasure will just work without any
change.  Just need to additionally store the LUKS header size, which was
previous stored in the sector_start, for use in the
get_sectors_{used,unused,unallocated}() calculations.

Bug 775932 - Refactor mostly applying of operations
2016-12-12 13:15:34 -07:00
Mike Fleetwood 0b359a5490 Refactor GParted_Core::copy() (#775932)
Split out the switch statement selecting the copy implementation and
associated copy file system operation detail message into a separate
copy_filesystem() method, matching how a number of other operations are
coded.  This is why the previous copy_filesystem() methods needed
renaming.

Re-write the remaining copy() into if-operation-fails-return-false style
to simplify it.  Re-write final complicated conditional check repair and
maximise file system into separate positive if conditions for swap and
larger partition to make it understandable.

The min_size parameter to copy() was queried from the partition_src
parameter also passed to copy().  Drop the parameter and query inside
copy() instead.

Bug 775932 - Refactor mostly applying of operations
2016-12-12 13:15:34 -07:00
Mike Fleetwood fd56d7be57 Rename copy_filesystem() methods (#775932)
Rename GParted_Core methods:
    copy_filesystem(4 params)  -> copy_filesystem_internal()
    copy_filesystem(5 params)  -> copy_filesystem_internal()
    copy_filesystem(10 params) -> copy_blocks()

See the following commit for the desire to do this.

Bug 775932 - Refactor mostly applying of operations
2016-12-12 13:15:34 -07:00
Mike Fleetwood fed2595d6d Rename file and class to CopyBlocks (#775932)
Files were named Block_Copy and the class was named block_copy.  Change
to the primary naming convention of CamelCase class name and matching
file names.

Also make CopyBlocks::copy_block() a private method as it is only used
internally within the class.

Bug 775932 - Refactor mostly applying of operations
2016-12-12 13:15:34 -07:00
Mike Fleetwood a5f2c9937b Refactor activate_mount_partition() and toggle_busy_state() (#775932)
These two methods had a lot of repeated and common code.  Both determine
if the partition has any pending operations, notify the user that
changing the busy status can not be performed, and report any errors
when changing the status.

Extract the common code into sub-functions check_toggle_busy_allowed()
and show_toggle_failure_dialog() to handle showing the message dialogs.
Also refactor toggle_busy_state() to make it clear that it handles 5
cases of swapon, swapoff, activate VG, deactivate VG and unmount file
system.

Also remove out of date comment near the top of toggle_busy_state()
stating there can only be pending operations for inactive partitions is
out of date.  Some file systems can be resized while online and
partition naming is allowed whatever the busy status of the file system.

Bug 775932 - Refactor mostly applying of operations
2016-12-12 13:15:34 -07:00
Mike Fleetwood bfc16bd4a6 Refactor Win_GParted::unmount_partition() (#775932)
The primary reason to refactor unmount_partition() is to pass the
Partition object to be unmounted, rather than use member variable
selected_partition_ptr so that it doesn't have to handle the differences
between encrypted and non-encrypted Partition objects.  The calling
function can deal with that instead.  Then there were lots of small
reasons to change almost every other line too:
* Return success or failure rather than updating a passed pointer with
  the result.  Leftover from when the function used to be a separate
  thread:
      commit 52a2a9b00a
      Reduce threading (#685740)
* Pass updated error string by reference rather than by pointer.  Likely
  another leftover.
* Stop borrowing the updated error string as a local variable for the
  error output from the umount command.  Use new umount_error local
  variable instead.  Was bad practice making the code harder to
  understand.
* Rename failed_mountpoints to skipped_mountpoints to better reflect
  that it contains the mount points not attempted to be unmounted
  because two or more file systems are mounted at that point.
* Rename errors to umount_errors to better reflect it contains the
  errors from each failed umount command.
* Document the reason for mount points being skipped.
* Update the skipped mount points message to state definitely why they
  could not be unmounted rather than stating most likely.
* Simplify logic processing the error cases and return value.
* Made static because it no longer accesses any class members.
* Remove out dated "//threads.." comment from the header.  Another
  leftover from when the function use to be a separate thread.

Bug 775932 - Refactor mostly applying of operations
2016-12-12 13:15:16 -07:00
Mike Fleetwood 43f2a4bd08 Reorder and rename params to TreeView_Detail::load_partitions()
Reorder the parameters into the same order in which they occur in the
row, i.e. Name first, then Mount Point and finally Label.  Rename local
variables in load_partitions(1 param) and parameters of
load_partitions(5 params) prefixing with "show_" to make it clearer the
variables track if that column will be displayed or not.
2016-12-02 10:06:01 -07:00
Mike Fleetwood 9e932ec7d0 Fix detection of empty mount point column for encrypted file systems (#775475)
create_row() populates the values for each row to be displayed in the UI
from the relevant Partition object.  However load_partitions(5 params)
independently decided if the Name, Mount Point and Label columns were
empty and should be displayed.

Getting the mount point value is more complex for encrypted file systems
because it has to call get_mountpoints() on the inner encrypted
Partition object.  load_partitions(5 params) didn't account for this.

Fix by making create_row() both copy the values into each row and at the
same time check if they are empty to decide if they should be displayed
or not.

Bug 775475 - Mount Point column displayed for encrypted file systems
             even when empty
2016-12-02 09:56:29 -07:00
Mike Fleetwood 7ea22f1190 Make GParted exit when closed before the initial load completes (#771816)
If the GParted main window is closed before the initial device load
completed gpartedbin never exits.  The main window closes but the
process sits there idle forever.  Subsequently running GParted reports
this error:
    # gparted
    The process gpartedbin is already running.
    Only one gpartedbin process is permitted.

If the user is running GParted from a desktop menu they will never see
this error so they will never know why GParted won't start any more.

More technically, it is if the main window is closed before the
Win_GParted::on_show() callback completes.

I assume the Gtk main loop doesn't setup the normal quit handling until
the on_show() callback finishes drawing the main window for the first
time.  Following this hint [1], move the initial device load from the
on_show() callback to immediately after it completes by using a run once
idle callback setup in on_show().

This looks exactly the same to the user except now gpartedbin exits when
the main window is closed during the initial device load.  Note that
GParted finished the device load before exiting.  This is exactly the
same as happens when exiting during subsequent device refreshes.

[1] How to know when a Gtk Window is fully shown?
    http://stackoverflow.com/questions/14663212/how-to-know-when-a-gtk-window-is-fully-shown

    "If you want to know when your main window appears the first time,
    it is far easier (and saner) add a g_idle_add after your show_all
    call."

Bug 771816 - GParted never exits if the main window is closed before the
             initial device load completes
2016-10-05 11:28:36 -06:00
Mike Fleetwood 85b6858702 Remove remaining vestiges of coloured text from the partition list
This commit stopped setting the text colours in the Partition, File
System and Mount Point columns to avoid hard coding text colours making
them impossible to read when using GNOME's High Contrast Inverse theme:
    ff2a6c00dd
    Changes post gparted-0.3.6 - code recreation from Source Forge

    * src/TreeView_Detail.cc: Removed text_color hard coding
      - Removed hard coding of Partition and Filesystem text_color
        which was based on if partition was TYPE_UNALLOCATED.
      - Removed hard coding of Mount text_color which was based
        on if partition was busy.  Lock symbol provides this indicator.
      - Closes GParted bug #413810 - Don't hardcode text colour in
        partition list

Now remove the remaining vestiges left behind.  Remove the unused color
text and mount_text_color columns from the tree model.  Also remove
setting of the column attributes which set the colour of the text in the
tree view from those unused columns in the tree model.

Unnecessary history.  Added by:
    b179990dc9
    show greyed-out mountpoint of unmounted partitions in the treeview
    as an improved way to identify partitions
    Bug #333027 -  Displaying unmounted partitions' default mount points
    in grey

and by commit only in CVS history:
    Bart Hakvoort <...> 2004-08-22 15:06:45
    Made text in Partition column darkgrey for unallocated. this offers
    more visual difference between partitions and unallocated space
2016-10-05 10:53:21 -06:00
Mike Fleetwood d64283fd1a Remove left behind typedef GParted_Core::MountMapping
Left behind by:
    63ec73dfda
    Split mount_info and fstab_info maps into separate Mount_Info module
2016-09-14 09:48:33 -06:00
Mike Fleetwood 63ec73dfda Split mount_info and fstab_info maps into separate Mount_Info module
The GParted_Core::mount_info and GParted_Core::fstab_info maps and the
methods that manipulate them are self-contained.  Therefore move them to
a separate Mount_Info module and reduce the size of the monster
GParted_Core slightly.
2016-08-06 09:47:58 -06:00
Mike Fleetwood 0785c5d7ef Remove unimplemented prototype DMRaid::partition_is_mounted_by_path() 2016-08-06 09:47:58 -06:00
Mike Fleetwood a94be2da05 Switch to static class interface for FS_Info
The FS_Info module has a pseudo multi-object interface and used the
constructor to load the cache.  However all the data in the class is
static.  An FS_Info object doesn't contain any member variables, yet was
needed just to call the member functions.

Make all the member functions static removing the need to use any
FS_Info objects and provide an explicit load_cache() method.
2016-08-06 09:47:58 -06:00
Mike Fleetwood 912766c2e1 Switch to a static interface for Proc_Partitions_Info
The Proc_Partitions_Info has a pseudo multi-object interface and uses
the constructor to load the cache.  However all the data in the class is
static.  A Proc_Partitions_Info object doesn't contain any member
variables, yet was needed just to call the member functions.

Make all the member functions static removing the need to use any
Proc_Partitions_Info objects and provide and explicit load_cache()
method.
2016-08-06 09:47:58 -06:00
Mike Fleetwood 91e5a0960e Remove remaining use of retired vol_id
Vol_id has been retired and removed from all supported distributions.
See earlier commit "Remove use of retired vol_id from FS_Info module
(#767842)" for more details.  Therefore remove it's use from GParted
entirely.
2016-08-06 09:47:58 -06:00
Mike Fleetwood 571304d2c6 Pre-populate BlockSpecial cache while reading /proc/partitions (#767842)
GParted is already reading /proc/partitions to get whole disk device
names.  The file also contains the major, minor device number of every
partition.  Use this information to pre-populate the cache in the
BlockSpecial class.

    # cat /proc/partitions
    major minor  #blocks  name

       8        0   20971520 sda
       8        1     512000 sda1
       8        2   20458496 sda2
    ...
       9        3    1047552 md3
     259        2     262144 md3p1
     259        3     262144 md3p2
    ...
     253        0   18317312 dm-0
     253        1    2097152 dm-1
     253        2    8383872 dm-2
     253        3    1048576 dm-3

Note that for Device-Mapper names (dm-*) the kernel is not using the
canonical user space names (mapper/*).  There is no harm in
pre-populating the cache with these names and will help if tools report
them too.  It is just that for DMRaid, LVM and LUKS, GParted uses the
canonical /dev/mapper/* names so will still have to call stat() once for
each such name.

For plain disks (sd*) and Linux Software RAID arrays (md*) the kernel
name is the common user space name too, therefore matches what GParted
uses and pre-populating does avoid calling stat() at all for these
names.

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood 003d6eff94 Cache looked up major, minor numbers in BlockSpecial class (#767842)
Creation of every BlockSpecial object used to result in a stat() OS
call.  On one of my test VMs debugging with 4 disks and a few partitions
on each, GParted refresh generated 541 calls to stat() in the
BlockSpecial(name) constructor.  However there were only 45 unique
names.  So on average each name was stat()ed approximately 12 times.

Cache the major, minor number associated with each name after starting
with a cleared cache for each GParted refresh.  This reduces these
direct calls to stat() to just the 45 unique names.

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood ce8fb1dd91 Use BlockSpecial in FS_Info module cache (#767842)
The FS_Info cache is loaded from "blkid" output and compares block
special names.  Therefore switch to using BlockSpecial objects so that
comparisons are performed by the major, minor device number instead.

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood 23da3ab9a8 Parse FS_Info cache into fields while loading (#767842)
FS_Info module caches the output from blkid as a single string and uses
regular expressions to find the line matching the requested block
special file name.  This is not compatible with using BlockSpecial
objects to represent block special files, and perform matching by major,
minor device number.  Therefore parse the blkid output into a vector of
structures containing the needed fields, ready for switching to
BlockSpecial objects in the following patch.

Interface to the module remains unchanged.

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood 8aa34f7baa Remove use of retired vol_id from FS_Info module (#767842)
Vol_id was removed from udev 142, released 2009-05-13, and udev switched
to using blkid instead [1].  All currently supported distributions use
later versions of udev (or systemd after the udev merge), except for
RedHat / CentOS 5 with udev 095.  However RedHat / CentOS 5 does provide
blkid and vol_id is found in udev specific /lib/udev directory not on
the PATH.  Therefore effectively vol_id is not available on any
supported distribution and blkid is always available.  Therefore remove
use of vol_id from the FS_Info module.  Less code to refactor and test
in following changes.

[1] delete vol_id and require util-linux-ng's blkid
    http://git.kernel.org/cgit/linux/hotplug/udev.git/commit/?id=f07996885dab45102492d7f16e7e2997e264c725

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood 2b013e494c Use BlockSpecial in SWRaid_Info module cache (#767842)
The SWRaid_Info cache is loaded from "mdadm" command output and
/proc/mdstat file.  It contains the member name which is used to access
the cache, therefore switch to using BlockSpecial objects so that
comparison is performed using the major, minor device number.

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood 7cd574cac5 Use BlockSpecial in LUKS_Info module cache (#767842)
The LUKS_Info module cache is loaded from "dmsetup" command and compares
block special files, therefore switch to using BlockSpecial objects so
that comparisons are performed by major, minor device number.

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood e4a8530b14 Overload is_dev_mounted() function (#767842)
Small optimisation which avoids constructing an extra BlockSpecial
object when determining if a btrfs member is mounted.  Rather than
extracting the name from the BlockSpecial object in
btrfs::get_mount_device() and re-constructing another BlockSpecial
object from that name in GParted_Core::is_dev_mounted(), pass the
BlockSpecial object directly.

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood abee66484f Use BlockSpecial objects in btrfs member cache (#767842)
There are no known errors which affect the remaining caches in GParted.
However those caches which compare block special devices will be changed
to use BlockSpecial objects so comparison is by major, minor device
number rather than by name.

Change btrfs member cache loaded from "btrfs filesystem show" output to
use BlockSpecial objects.

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood a800ca8b68 Add BlockSpecial into mount_info and fstab_info (#767842)
On some distributions having btrfs on top of LUKS encrypted partitions,
adding a second device and removing the first device used to mount the
file system causes GParted to no longer be able to report the file
system as busy or the mount points themselves.

For example, on CentOS 7, create a single btrfs file system and mount
it.  The provided /dev/mapper/sdb1_crypt name is reported, via
/proc/mounts, as the mounting device:
    # cryptsetup luksFormat --force-password /dev/sdb1
    # cryptsetup luksOpen /dev/sdb1 sdb1_crypt
    # mkfs.btrfs -L encrypted-btrfs /dev/mapper/sdb1_crypt
    # mount /dev/mapper/sdb1_crypt /mnt/1

    # ls -l /dev/mapper
    total 0
    lrwxrwxrwx. 1 root root       7 Jul  2 14:15 centos-root -> ../dm-1
    lrwxrwxrwx. 1 root root       7 Jul  2 14:15 centos-swap -> ../dm-0
    crw-------. 1 root root 10, 236 Jul  2 14:15 control
    lrwxrwxrwx. 1 root root       7 Jul  2 15:14 sdb1_crypt -> ../dm-2
    # fgrep btrfs /proc/mounts
    /dev/mapper/sdb1_crypt /mnt/1 btrfs rw,seclabel,relatime,space_cache 0 0

Add a second device to the btrfs file system:
    # cryptsetup luksFormat --force-password /dev/sdb2
    # cryptsetup luksOpen /dev/sdb2 sdb2_crypt
    # btrfs device add /dev/mapper/sdb2_crypt /mnt/1

    # ls -l /dev/mapper
    ...
    lrwxrwxrwx. 1 root root       7 Jul  2 15:12 sdb2_crypt -> ../dm-3
    # btrfs filesystem show /dev/mapper/sdb1_crypt
    Label: 'encrypted-btrfs'  uuid: 45d7b1ef-820c-4ef8-8abd-c70d928afb49
            Total devices 2 FS bytes used 32.00KiB
            devid    1 size 1022.00MiB used 12.00MiB path /dev/mapper/sdb1_crypt
            devid    2 size 1022.00MiB used 0.00B path /dev/mapper/sdb2_crypt

Remove the first mounting device from the btrfs file system.  Now the
non-canonical name /dev/dm-3 is reported, via /proc/mounts, as the
mounting device:
    # btrfs device delete /dev/mapper/sdb1_crypt /mnt/1

    # btrfs filesystem show /dev/mapper/sdb2_crypt
    Label: 'encrypted-btrfs'  uuid: 45d7b1ef-820c-4ef8-8abd-c70d928afb49
            Total devices 1 FS bytes used 96.00KiB
            devid    2 size 1022.00MiB used 144.00MiB path /dev/mapper/sdb2_crypt
    # fgrep btrfs /proc/mounts
    /dev/dm-3 /mnt/1 btrfs rw,seclabel,relatime,space_cache 0 0
    # ls -l /dev/dm-3
    brw-rw----. 1 root disk 253, 3 Jul  2 15:12 /dev/dm-3

GParted loads the mount_info mapping from /proc/mounts and with it the
/dev/dm-3 name.  When GParted is determining if the encrypted btrfs file
system is mounted or getting the mount points it is using the
/dev/mapper/sdb2_crypt name.  Therefore no information is found and the
file system is incorrectly reported as unmounted.

Fix by changing mount_info and fstab_info to use BlockSpecial objects
instead of strings so that matching is performed by major, minor device
numbers rather than by string compare.  Note that as BlockSpecial
objects are used as the key of std::map [1] mappings operator<() [2]
needs to be provided to order the key values.

[1] std::map
    http://www.cplusplus.com/reference/map/map/
[2] std::map::key_comp
    http://www.cplusplus.com/reference/map/map/key_comp/

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood ab2d4f5ee6 Create BlockSpecial class and use in LVM2_PV_Info (#767842)
In some cases creating an LVM2 Physical Volume on top of a DMRaid array
reports no usage information and this partition warning:
    Unable to read the contents of this file system!
    Because of this some operations may be unavailable.
    The cause might be a missing software package.
    The following list of software packages is required for lvm2
    pv file system support: lvm2.

For example on Ubuntu 14.04 LTS (with GParted built with
--enable-libparted-dmraid) create an LVM2 PV in a DMRaid array
partition.  GParted uses this command:
    # lvm pvcreate -M 2 /dev/mapper/isw_bacdehijbd_MyArray0p2

But LVM reports the PV having a different name:
    # lvm pvs
      PV                                                VG   Fmt  Attr PSize PFree
      /dev/disk/by-id/dm-name-isw_bacdehijbd_MyArray0p2      lvm2 a--  1.00g 1.00g

This alternate name is loaded into the LVM2_PV_Info module cache.  Hence
when GParted queries partition /dev/mapper/isw_bacdehijbd_MyArray0p2 it
has no PV information against that name and reports unknown usage.

However they are actually the same block special device; major 252,
minor 2:
    # ls -l /dev/mapper/isw_bacdehijbd_MyArray0p2
    brw-rw---- 1 root disk 252, 2 Jul  2 11:09 /dev/mapper/isw_bacdehijbd_MyArray0p2

    # ls -l /dev/disk/by-id/dm-name-isw_bacdehijbd_MyArray0p2
    lrwxrwxrwx 1 root root 10 Jul  2 11:09 /dev/disk/by-id/dm-name-isw_bacdehijbd_MyArray0p2 -> ../../dm-2
    # ls -l /dev/dm-2
    brw-rw---- 1 root disk 252, 2 Jul  2 11:09 /dev/dm-2

To determine if two names refer to the same block special device their
major, minor numbers need to be compared, instead of string comparing
their names.

Implement class BlockSpecial which encapsulates the name and major,
minor numbers for a block special device.  Also performs comparison as
needed.  See bug 767842 comments 4 and 5 for further investigation and
decision for choosing to implement a class.

Replace name strings in the LVM2_PV_Info module with BlockSpecial
objects performing correct block special device comparison.

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood 0f4df8dfd1 Remove now unused Proc_Partitions_Info::get_alternate_paths() (#767842)
Now Device and Partition objects only have a single path,
get_alternate_paths() is never called.  Remove the method and population
of the private alternate_paths_cache member that went with it.

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood 40f39bdbe2 Rename Partition::add_path() to set_path() (#767842)
To reflect that there is now only a single path in the Partition object
now.  Also get rid of the now unneeded optional clear_paths parameter
which was only relevant when there was a vector of paths.

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood 214255eda3 Simplify Partition object to a single path (#767842)
Change from a vector of paths to a single path member in the Partition
object.  Remove add_paths() and get_paths() methods.  Keep add_path()
and get_path().

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood 1dc8a0c628 Rename Device::add_path() to set_path() (#767842)
To reflect that there is only a single path in the Device object now.
Also get rid of the now unneeded optional parameter which was only
relevant when there was a vector of paths.

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood 902afaa010 Simplify Device object to a single path (#767842)
Background

GParted stored a list of paths for Device and Partition objects.  It
sorted this list [1][2] and treated the first specially as that is what
get_path() returned and was used almost everywhere; with the file system
specific tools, looked up in various *_Info caches, etc.

[1] Device::add_path(), ::add_paths()
[2] Partition::add_path(), ::add_paths()

Mount point display [3] was the only bit of GParted which really worked
with the path list.  Busy file system detection [4] just used the path
provided by libparted, or for LUKS /dev/mapper/* names.  It checked that
single path against the mounted file systems found from /proc/mounts,
expanded with additional block device names when symlinks were
encountered.

[3] GParted_Core::set_mountpoints() -> set_mountpoints_helper()
[4] GParted_Core::set_device_partitions() -> is_busy()
    GParted_Core::set_device_one_partition() -> is_busy()
    GParted_Core::set_luks_partition() -> is_busy()

Having the first path, by sort order, treated specially by being used
everywhere and virtually ignoring the others was wrong, complicated to
remember and difficult code with.  As all the additional paths were
virtually unused and made no difference, remove them.  The "improved
detection of mountpoins, free space, etc.." benefit from commit [5]
doesn't seem to exist.  Therefore simplify to a single path for Device
and Partition objects.

[5] commit 6d8b169e73
    changed the way devices and partitions store their device paths.
    Instead of holding a 'realpath' and a symbolic path we store paths
    in a list.  This allows for improved detection of mountpoins, free
    space, etc..

This patch

Simplify the Device object from a vector of paths to a single path.
Remove add_paths() and get_paths() methods.  Keep add_path() and
get_path() for now.

Bug 767842 - File system usage missing when tools report alternate block
             device names
2016-08-06 09:47:58 -06:00
Mike Fleetwood 8ac3a0e4ad Recognise GRUB2 core.img (#766989)
Recognise GRUB2 core.img boot code written to a partition without a file
system.  Such setups are possible/likely with GPT partitioned disks as
there is a specific partition type reserved for it [1][2]:
    21686148-6449-6E6F-744E-656564454649  (BIOS Boot partition)

[1] GUID Partition Table, Partition types
    https://en.wikipedia.org/wiki/GUID_Partition_Table#Partition_type_GUIDs

[2] BIOS boot partition
    https://en.wikipedia.org/wiki/BIOS_boot_partition

Bug 766989 - zfsonline support - need file system name support for ZFS
             type codes
2016-06-15 12:45:05 -06:00
Mike Fleetwood 1f2a50544d Prevent assert failure from OperationCheck::get_partition_new() (#767233)
Composing these operations caused GParted to abort on an assert failure:
(1) Check an existing partition,
(2) Create a new partition,
(3) Delete new partition.

    # ./gpartedbin
    ======================
    libparted : 2.4
    ======================
    **
    ERROR:OperationCheck.cc:40:virtual GParted::Partition& GParted::OperationCheck::get_partition_new(): assertion failed: (false)
    Aborted (core dumped)

    # gdb ./gpartedbin core.8876 --batch --quiet --ex backtrace -ex quit
    [New Thread 8876]
    [New Thread 8879]
    [Thread debugging using libthread_db enabled]
    Core was generated by `./gpartedbin'.
    Program terminated with signal 6, Aborted.
    #0  0x000000361f2325e5 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
    64	  return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig);
    #0  0x000000361f2325e5 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
    #1  0x000000361f233dc5 in abort () at abort.c:92
    #2  0x0000003620a67324 in g_assertion_message (domain=<value optimized out>, file=<value optimized out>, line=<value optimized out>, func=0x50f400 "virtual GParted::Partition& GParted::OperationCheck::get_partition_new()", message=0x1d37a00 "assertion failed: (false)") at gtestutils.c:1358
    #3  0x0000003620a678f0 in g_assertion_message_expr (domain=0x0, file=0x50f1a8 "OperationCheck.cc", line=40, func=0x50f400 "virtual GParted::Partition& GParted::OperationCheck::get_partition_new()", expr=<value optimized out>) at gtestutils.c:1369
    #4  0x0000000000498e21 in GParted::OperationCheck::get_partition_new (this=0x1d1bb30) at OperationCheck.cc:40
    #5  0x00000000004c66ec in GParted::Win_GParted::activate_delete (this=0x7fff031c3e30) at Win_GParted.cc:2068
    ...

When Win_GParted::activate_delete() was stepping through the operation
list removing operations (2 & 3 in the above recreation steps) which
related to the new partition never to be created it called
get_partition_new() on all operations in the list.  This included
calling get_partition_new() on the check operation (1 in the above
recreation steps).  As partition_new was not set or used by the check
operation get_partition_new() asserted false and crashed GParted.

Fix by populating the partition_new member in OperationCheck objects,
thus allowing get_partition_new() to be called on the object.  As a
check operation doesn't change any partition boundaries or file system
attributes, just duplicate the new partition from the original
partition.

Bug 767233 - GParted core dump on assert failure in
             OperationDelete::get_partition_new()
2016-06-05 13:14:34 -06:00
Mike Fleetwood cc7e412bc6 Only enable ext4 64bit feature when required (#766910)
E2fsprogs version 1.43 always creates 64bit ext4 file systems by default
[1][2] regardless of the partition size.  Previously it only enabled the
64bit feature when required on ext4 volumes 16 TiB and larger.  Also
note that RHEL / CentOS 7 always create 64bit ext4 file systems by
default from e2fsprogs 1.42.9 [3].

(At least some versions of) Grub 2 and syslinux boot loaders don't work
with 64bit ext4 file systems [4][5][6].  For maximum boot loader
compatibility make GParted implement what mke2fs previously did, only
setting the 64bit feature on volumes 16 TiB and larger and clearing it
otherwise.  Only applied to mkfs.ext4 version 1.42 and later.

[1] Release notes, E2fsprogs 1.43 (May 17, 2016)
    http://e2fsprogs.sourceforge.net/e2fsprogs-release.html#1.43

    "Mke2fs will now create file systems with the metadata_csum and
    64bit features enabled by default".

[2] http://git.kernel.org/cgit/fs/ext2/e2fsprogs.git/commit/?id=cd27af3ecb83e8fd1e3eaa14994284a1818c7c15
    mke2fs: enable the metadata_csum and 64bit features by default

[3] Comment 20 and 21 in Red Hat bug 1099237
    https://bugzilla.redhat.com/show_bug.cgi?id=1099237#c20

    "..., is rhel7 default behavior w.r.t. 64 bit really different from
    upstream ?

    Yes it is. This is what we have in RHEL7:
    Patch6: e2fsprogs-1.42.9-enable-64bit-feature-by-default.patch
    it fixed this bz: https://bugzilla.redhat.com/show_bug.cgi?id=982871
    and this is upstream proposal:
    http://www.spinics.net/lists/linux-ext4/msg42294.html"

[4] Grub 2 not working on Slackware with 64bit EXT4
    http://www.linuxquestions.org/questions/slackware-14/grub-mkconfig-error-in-slackware-current-64-bit-4175580544/

[5] Syslinux not working on Slackware with 64bit EXT4
    http://www.linuxquestions.org/questions/slackware-14/slackware64-current-5-20-2016-syslinux-booting-and-ext4-formatting-4175580324/

[6] Syslinux not working on RHEL 7 with 64bit EXT4
    Bug 1099237 - rhel7 ext4 defaults to 64 bit, which extlinux can't reliably read
    https://bugzilla.redhat.com/show_bug.cgi?id=1099237

Bug 766910 - Multiple boot loaders don't work on 64bit EXT4 file systems
2016-06-05 09:40:11 -06:00
Mike Fleetwood a681f9f637 Replace 32-bit member variable "index" with wider local variables (#764658)
The previous commit (Fix crash reading NTFS usage when there is no
/dev/PTN entry) identified that the FileSystem member variable "index"
is too small on 64-bit machines.  Also this member variable stores no
FileSystem class information and was being used as a local variable.

Replace with local variables of the of the correct type, wide enough to
store the npos not found value.

Bug 764658 - GParted crashes when reading NTFS usage when there is no
             /dev/PTN entry
2016-04-07 09:56:00 -06:00
Mike Fleetwood 1358a5f4fe Use a single progress bar for the internal block copy operation (#762367)
As part of the internal block copy operation 5 initial ranges of blocks
are copied using different block sizes to determine the fastest.  Then
the remainder is copied using the fastest block size.  Each of these
copies reports progress independently, so during the benchmarking phase
the progress bar flashes 5 times as it goes from 0 to 100% in a fraction
of a second, before showing the progress of the remainder.

This looks bad, so report a single progress bar for all the ranges of
blocks copied in a single copy operation.

Already have variables done and length which track progress within each
copied range; and total_done which records amount copied in previous
ranges.  Just add total_length to allow overall progress to be reported.

Bug 762367 - Use a single progress bar for the whole of the internal
             copy operation
2016-02-23 10:41:20 -07:00
Mike Fleetwood 6d28a62077 Display progress of NTFS file system specific copy operation (#762366)
Copying of ntfs is performed using ntfsclone, which writes progress
indication to standard output like this:

    # ntfsclone -f /dev/sdb2 /dev/sdb1 2> /dev/null
    NTFS volume version: 3.1
    Cluster size       : 4096 bytes
    Current volume size: 21474832384 bytes (21475 MB)
    Current device size: 21474836480 bytes (21475 MB)
    Scanning volume ...
    100.00 percent completed
    Accounting clusters ...
    Space in use       : 1832 MB (8.5%)
    Cloning NTFS ...
    100.00 percent completed
    Syncing ...

Add ntfsclone progress tracker for ntfsclone command.  Deliberately
doesn't stop the progress bar.  See comment in ntfs::clone_progress()
for the explanation.

Bug 762366 - Add progress bar to NTFS file system specific copy method
2016-02-23 10:02:03 -07:00
Mike Fleetwood 438b35aed9 Connect timed progress tracking callbacks inside execute_command() (#760709)
The timed progress tracking callback for execution of xfs copy follows
this pattern:

    sigc::connection c;
    ...
    c = Glib::signal_timeout().connect( ... sigc::mem_fun( *this, &xfs::copy_progress ) ..., 500 /*ms*/ );
    ... execute_command( ... );
    c.disconnect();

As with output progress tracking callbacks for ext2/3/4 and ntfs file
system specific commands, pass the callback slot and a flag into
execute_command() and connect the timed callback inside.  This
simplified the pattern to:

    ... execute_command( ...|EXEC_PROGRESS_TIMED,
                         static_cast<TimedSlot>( sigc::mem_fun( *this, &xfs::copy_progress ) ) );

NOTE:
The type of sigc::mem_fun() doesn't allow the compiler to choose between
the two overloaded variants of execute_command() with the fourth
parameter of either (full types without typedefs of StreamSlot and
TimedSlot respectively):
    sigc::slot<void, OperationDetail *> stream_progress_slot
    sigc::slot<bool, OperationDetail *> timed_progress_slot
Therefore have to cast the result of all callback slots to the relevant
type.  Hence:
    static_cast<StreamSlot>( sigc::mem_fun( *this, &{CLASS}::{NAME}_progress ) )
    static_cast<TimedSlot>( sigc::mem_fun( *this, &xfs::copy_progress ) )

References:
*   [sigc] Functor not resolving between overloaded methods with
    different slot types
    https://mail.gnome.org/archives/libsigc-list/2016-February/msg00000.html
*   Bug 306705 - Can't overload methods based on different slot<>
    parameters.
    https://bugzilla.gnome.org/show_bug.cgi?id=306705

Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific
             copy methods
2016-02-12 09:09:57 -07:00
Mike Fleetwood e67bbe906f Remove the unnecessary signal_progress (#760709)
For the relevant stream from a file system specific command being
tracked, there were 2 callbacks attached: update_command_output() and
update_command_progress().  When called, update_command_progress() just
emitted signal_progress to call the file system specific progress
tracker callback.  Like this:

    signal_update.emit() -> update_command_output()
                         -> update_command_progress()
                                signal_progress.emit() -> {CLASS}::{NAME}_progress()

Instead just connect the file system specific progress tracker callback
directly to signal_update and bypass the unnecessary
update_command_progress() method and the signal_progress signal.  Like
this:

    signal_update.emit() -> update_command_output()
                         -> {CLASS}::{NAME}_progress()

Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific
             copy methods
2016-02-12 09:09:57 -07:00
Mike Fleetwood c00927c23d Connect output progress tracking callbacks inside execute_command() (#760709)
All the output progress tracking callbacks for execution of ext2/3/4 and
ntfs file system specific commands followed this pattern:

    sigc::connection c = signal_progress.connect( sigc::mem_fun( *this, &ext2::..._progress ) );
    bool success = ! execute_command( ... );
    c.disconnect();
    return success;

Instead, pass the callback slot and a flag into execute_command() and
connect the callback inside.  This simplifies the pattern to:

    return ! execute_command( ...|EXEC_PROGRESS_STDOUT,
                              sigc::mem_fun( *this, &ext2::..._progress ) );

Note that as the progress tracking callbacks are only registered against
updates to the relevant stream from the tracked commands they won't be
called when the other stream is updated any more.

Also note that signal_progress is a member of the FileSystem class and
derived objects so lives as long as GParted is running, therefore the
progress tracking callbacks need explicitly disconnecting at the end of
execute_command().  However signal_update is a member of the PipeCapture
class of which the output and error local variables in execute_command()
are types.  Therefore there is no need to explicitly disconnect the
signal_update callbacks as they will be destructed along with the
callback slots when they go out of scope at the end of the
execute_command() method.

Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific
             copy methods
2016-02-12 09:09:57 -07:00
Mike Fleetwood 27e30a570f Remove unused OperationDetail members (#760709)
Remove unused members: fraction and progress_text from the
OperationDetail class now that the ProgressBar class has superseded
their use.  This also allows removal of timer_global member from the
copy_blocks class.  Timer_global was only used to track the elapsed time
copying blocks and allow the remaining time to be estimated and written
into progress_text.  The ProgressBar class also does this itself
internally.

Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific
             copy methods
2016-02-12 09:09:57 -07:00
Mike Fleetwood b1313281bd Simplify use of the progress bar via OperationDetail (#760709)
Most of the file system specific command progress trackers followed this
pattern:

    void {CLASS}::{NAME}_progress( OperationDetail *operationdetail )
    {
            ProgressBar & progressbar = operationdetail->get_progressbar();
            // parse output for progress and target values
            if ( // have progress and target values )
            {
                    if ( ! progressbar.running() )
                            progressbar.start( target );
                    progressbar.update( progress );
                    operationdetail->signal_update( *operationdetail );
            }
            else if ( // found progress finished )
            {
                    if ( progressbar.running() )
                            progressbar.stop();
                    operationdetail->signal_update( *operationdetail );
            }
    }

That is a lot of repetition handling progress bar updates and
OperationDetail object update signalling.  Remove the need for direct
access to the single ProgressBar object and provide these two
OperationDetail methods instead:
    // Start and update in one
    run_progressbar( progress, target, optional text_mode );
    stop_progressbar();

Now the file system specific command progress trackers can become:

    void {CLASS}::{NAME}_progress( OperationDetail *operationdetail )
    {
            // parse output for progress and target values
            if ( // have progress and target values )
            {
                    operationdetail->run_progressbar( progress, target );
            }
            else if ( // found progress finished )
            {
                    operationdetail->stop_progressbar();
            }
    }

Make ProgressBar::get_progressbar() a private method to enforce use of
the new way to access the progress bar via the run_progress() and
stop_progressbar() methods.  Then make the Dialog_Progress a friend
class to OperationDetail so that the Apply pending operations dialog can
still access the single ProgressBar object for its querying needs.

Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific
             copy methods
2016-02-12 09:09:57 -07:00
Mike Fleetwood 32622f4d57 Display progress of ext2/3/4 file system specific copy and move operations (#760709)
Using e2image to copy a file system looks like this.  (Intermediate
progress lines which are constantly overwritten are indicated with ">").
    # e2image -ra -p /dev/sdb4 /dev/sdb5
    e2image 1.42.13 (17-May-2015)
    Scanning inodes...
>   Copying 0 / 276510 blocks (0%)
>   Copying 8845 / 276510 blocks (3%)
>   Copying 48433 / 276510 blocks (18%)
>   Copying 77135 / 276510 blocks (28%)
>   Copying 111311 / 276510 blocks (40%)
>   Copying 137039 / 276510 blocks (50%)
>   Copying 166189 / 276510 blocks (60%) 00:00:03 remaining at 108.20 MB/s
>   Copying 190285 / 276510 blocks (69%) 00:00:03 remaining at 106.19 MB/s
>   Copying 209675 / 276510 blocks (76%) 00:00:02 remaining at 102.38 MB/s
>   Copying 238219 / 276510 blocks (86%) 00:00:01 remaining at 103.39 MB/s
>   Copying 256692 / 276510 blocks (93%) 00:00:00 remaining at 100.27 MB/s
    Copied 276510 / 276510 blocks (100%) in 00:00:10 at 108.01 MB/s

Note that the copying figures are reported in file system block size
units and the progress information is written to stderr, hence needing
these two previous commits:
    Record file system block size where known (#760709)
    Call any FS specific progress trackers for stderr updates too (#760709)

Add progress tracking function for e2image command.  Also tracks when
the text progress indicator has passed in the output so that the
progress bar can be stopped as well as started when needed.

Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific
             copy methods
2016-02-12 09:09:57 -07:00
Mike Fleetwood 324d99a172 Record file system block size where known (#760709)
Record the file system block size in the Partition object.  Only
implemented for file systems when set_used_sectors() method has already
parsed the value or can easily parse the value from the existing
executed command(s).

Needed for ext2/3/4 copies and moves performed using e2image so that
they can be tracked in bytes by the ProgressBar class as e2image reports
progress in file system block size units.

Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific
             copy methods
2016-02-12 09:09:57 -07:00
Mike Fleetwood 809a7e0954 Display progress of XFS file system specific copy operation (#760709)
XFS uses a file system specific method to copy the partition using
"xfsdump | xfsrestore".  Monitor progress by periodically querying the
destination file system usage and comparing to the source file system
usage.  Use 0.5 seconds as the polling interval to match that used by
the internal block copying algorithm.

NOTE:
The number of used blocks in the source and destination file system will
be very close but may not match exactly.  I have seen an XFS copy finish
with the following progress text:
    1.54 GiB of 1.50 GiB copied (-00:00:02 remaining)
Allow the progress bar to overrun like this as it is informing the user
that it actually copied a little more data and took a little longer than
expected.  Needs these two previous commits to correctly round and
format the negative time remaining:
    Fix rounding of negative numbers (#760709)
    Fix formatting of negative time values (#760709)

Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific
             copy methods
2016-02-12 09:09:57 -07:00
Mike Fleetwood 608060f82d Update ext2 resize progress tracker to use the new ProgressBar (#760709)
Adapt the ext2 resize progress tracker to the new ProgressBar class.
Also update the progress function to track when text progress bars have
completely passed in the output so that the progress bar can be stopped
as well as started when needed.

Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific
             copy methods
2016-02-12 09:09:56 -07:00
Mike Fleetwood c3669c3a96 Add a single ProgressBar for all OperationDetail objects (#760709)
1) Multiple progress bars

The OperationDetail class contains member fraction which is used to feed
data to the current operation progress bar shown in the Applying pending
operations dialog.  Dialog_Progress::on_signal_update() gets called for
every updated OperationDetail object and depending on whether fraction
is > 0.0 or not, switches between showing a growing or pulsing progress
bar.  This leads to the conclusion that every OperationDetail object
currently being updated is effectively driving the single on screen
progress bar with different data.

The Copy_Blocks code is careful to update text and faction in a single
OperationDetail object and everything is good.  The on screen progress
bar is switched into growing mode and then grows to 100%.

Since external command output is updated in real time [1] there are two
OperationDetail objects, one for stdout and one for stderr, which are
updated whenever data is read from the relevant stream.  Also now that
progress is interpreted from some external command output [2][3][4] a
separate OperationDetail object is getting updated with the progress
fraction.  (Actually the grandparent OperationDetail of the ones
receiving stdout and stderr updates as used by the file system specific
*_progress() methods).  In the normal case of an external command
which is reporting it's progress two OperationDetails are constantly
being updated together, the OperationDetail object tracking stdout and
it's grandparent receiving progress fraction updates.  This causes the
the code in Dialog_Progress::on_signal_update() to constantly switch
between growing and pulsing progress bar mode.  The only reason this
doesn't flash the progress bar is because the stdout OperationDetail
object is updated first and before the 100 ms timeout fires to pulse the
bar, it's grandparent is updated with the new fraction to keep growing
the bar instead.

2) Common code

The Copy_Blocks code currently tracks the progress of blocks copied
against target amount, which it has to do anyway.  That information is
then used to generate the text and fraction to update into the
OperationDetail object and drive the on screen progress bar.  This same
level of tracking is wanted for the XFS and ext2/3/4 file system
specific copy methods.

Conclusion and solution

Having multiple sources of progress bar data is a problem and makes it
clear that there must be only one source of progress data.  Also some
code can be shared for tracking the amount of blocks copied and
generating the display.

Therefore have a single ProgressBar object which is used everywhere.

This commit

It just creates a single ProgressBar object which is available via all
OperationDetail objects and Copy_Blocks is updated accordingly.  Note
that the ProgressBar still contains debugging and that the GUI progress
bar of the current operation is still driven via the fraction member in
any OperationDetail object.

Referenced commits:

[1] 52a2a9b00a
    Reduce threading (#685740)

[2] ae434579e1
    Display progress for e2fsck (#467925)
[3] baea186138
    Display progress for mke2fs (#467925)
[4] 57b028bb8e
    Display progress during resize (#467925)

Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific
             copy methods
2016-02-12 09:09:56 -07:00
Mike Fleetwood 0ca8ed7369 Write a generic progress bar class (#760709)
Write a generic progress bar class.  Has the following features:
* Has separate progress and target numbers, rather than a single
  completion fraction, to enable the the next feature.
* Optionally generates text reporting the amount of data copied using
  the progress and target numbers like this:
      "1.00 MiB of 16.00 MiB copied"
* After running for 5 seconds, also add estimated remaining time.
  (Waits to allow the data copying rate to settle down a little before
  estimating the remaining time).  Looks like this:
      "1.00 MiB of 16.00 MiB copied (00:01:59) remaining)"

The ProgressBar class is not driving the visual progress bar yet.  It
has just been added into the internal block copy algorithm and generates
debug messages showing the progress bar is operating correctly.
Debugging looks like this:

    DEBUG: ProgressBar::start(target=2.0636e+09, text_mode=PROGRESSBAR_TEXT_COPY_BYTES)
    DEBUG: ProgressBar::update(progress=1.30023e+08) m_fraction=0.0630081 m_text="124.00 MiB of 1.92 GiB copied"
    DEBUG: ProgressBar::update(progress=2.67387e+08) m_fraction=0.129573 m_text="255.00 MiB of 1.92 GiB copied"
    DEBUG: ProgressBar::update(progress=4.0475e+08) m_fraction=0.196138 m_text="386.00 MiB of 1.92 GiB copied"
    ...
    DEBUG: ProgressBar::update(progress=1.13351e+09) m_fraction=0.549289 m_text="1.06 GiB of 1.92 GiB copied (00:00:04 remaining)"
    DEBUG: ProgressBar::update(progress=1.26249e+09) m_fraction=0.611789 m_text="1.18 GiB of 1.92 GiB copied (00:00:04 remaining)"
    DEBUG: ProgressBar::update(progress=1.39041e+09) m_fraction=0.67378 m_text="1.29 GiB of 1.92 GiB copied (00:00:03 remaining)"
    ...
    DEBUG: ProgressBar::update(progress=1.97552e+09) m_fraction=0.957317 m_text="1.84 GiB of 1.92 GiB copied (00:00:00 remaining)"
    DEBUG: ProgressBar::update(progress=2.0636e+09) m_fraction=1 m_text="1.92 GiB of 1.92 GiB copied"
    DEBUG: ProgressBar::stop()

Bug 760709 - Add progress bars to XFS and EXT2/3/4 file system specific
             copy methods
2016-02-12 09:09:56 -07:00
Mike Fleetwood 2d910494d3 Display messages for encrypted file systems (#760080)
At the moment any messages for an encrypted file system aren't shown,
only messages from the outer PartitionLUKS object are shown.  Also in
Win_GParted::activate_paste() the selected Partition object, possibly
a derived PartitionLUKS, is cloned and the messages cleared.

Therefore a set of accessor methods must be provided to query and modify
partition messages.  Messages will be stored in the Partition object to
which they are added and retrieved from all.  So in the case of a
derived PartitionLUKS they will be retrieved from the messages vector of
the PartitionLUKS object itself and the messages vector for the
encrypted file system it contains.

To replace code like this in GParted_Core:

    partition_temp->messages = messages;

We might naturally provide a set_messages() method which assigns the
messages vector and is used like this:

    partition_temp->set_messages( messages );

However on a PartitionLUKS object what should set_messages() do?  By the
name it will replace any existing messages in the PartitionLUKS object
itself, but what should happen to the messages for the contained
encrypted Partition object?  Should they be cleared or left alone?
Rather than implement set_messages() with unclear semantics implement
append_messages(), which in the PartitionLUKS object case will clearly
leave any messages for the contained encrypted Partition object alone.
Append_messages() is then used to add messages as the Partition or
PartitionLUKS objects when populating the data in GParted_Core.

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:41 -07:00
Mike Fleetwood f91d7e19dd Add encryption section into the Information dialog (#760080)
For LUKS formatted partitions add an encryption section into the
Information dialog and display the type of encryption, path, UUID and
status of the encryption.

The file system section continues to display appropriate file system
details, including the partition graphic with the file system specific
border colour and correct usage.  The details will either be of a plain
file system, an encrypted file system, or nothing when there is no open
dm-crypt mapping, leaving the encrypted file system inaccessible.
Should there be LUKS encryption directly within LUKS encryption then the
details of the inner encryption will be displayed in the file system
section.  However this configuration will not be further supported by
GParted.

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:41 -07:00
Mike Fleetwood cb24aa4be1 Display usage of encrypted file systems (#760080)
There is already the set of methods in the Partition class to report the
file system usage.  Virtualise them and provide PartitionLUKS specific
implementations to calculate the usage of a file system wrapped in LUKS
encryption.

See the ascii art and comment in PartitionLUKS.cc for the details of
those calculations.

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:41 -07:00
Mike Fleetwood 38a790d745 Display the label of encrypted file systems (#760080)
LUKS headers don't provide any concept of label.  Also there is already
the method Partition::get_filesystem_label() for getting the *file
system* label, so virtualise it and provide an appropriate
implementation to get the label of an encrypted file system represented
within a derived PartitionLUKS object.  This causes the label to be
displayed correctly in the main window.

It also happens to display the encrypted file system label in the
Information dialog for a LUKS formatted partition.  However the whole
Information dialog will be addressed differently in a following commit.

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:41 -07:00
Mike Fleetwood cb3cc505ce Display "[Encrypted] FSTYPE" in the File System column (#760080)
In the File System column in the GUI, when there is an open dm-crypt
mapping, display the colour square for the encrypted file system within
and the text as "[Encrypted] FSTYPE".  For closed mappings nothing can
be known about the encrypted file system within so continue to display a
purple square and the text "[Encrypted]".

Looks like:

    Partition        | File System
      ...
      /dev/sdb3        # ext4
    v /dev/sdb4    *   # extended
        /dev/sdb5      # [Encrypted]
        /dev/sdb6  *   # [Encrypted] unknown
        /dev/sdb7  *   # [Encrypted] ext4

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:41 -07:00
Mike Fleetwood 6e294dda05 Remove Partition::color member (#760080)
Partition object represents a region of a disk and the file system
within.  GParted always displays the colour base of the type of the file
system.  Therefore remove the color member and always look it up from
the type of the file system as needed.

This makes one less member that will need virtual accessor methods with
different handling in the derived PartitionLUKS class.

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:40 -07:00
Mike Fleetwood c9a2986fb9 Populate encrypted Partition member inside PartitionLUKS (#760080)
When there exists an open dm-crypt mapping, populate the encrypted
Partition object representing the encrypted file system.

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:40 -07:00
Mike Fleetwood 99ff0c7628 Add PartitionLUKS class and create objects (#760080)
Absolute minimum implementation of a PartitionLUKS class which can be
constructed, polymorphically copied and destroyed.  Contains an
"encrypted" member of type Partition to represent the encrypted file
system within the LUKS format.

Create PartitionLUKS objects instead of base Partition objects when a
LUKS formatted partition is found.  Only the base Partition object
member values have been populated, and the "encrypted" member remains
blank at this point.

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:40 -07:00
Mike Fleetwood 9fee0c57ea Refactor set_used_sectors() to be called per partition (#760080)
This is the equivalent change as made to set_mountpoints() in an earlier
commit.  Change GParted_Core::set_used_sectors() from being called with
a vector of partitions and processing them all to being called per
partition.  This is in preparation for calling set_used_sectors() on a
single Partition object inside a PartitionLUKS object.

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:40 -07:00
Mike Fleetwood 1b731b93d7 Refactor set_mountpoints() to be called per partition (#760080)
Previously GParted_Core::set_mountpoints() was called with a vector of
partitions and processed them all.  Now make set_mountpoints() process a
single partition and push the calls to it down one level from
set_devices_thread() into set_device_partitions() and
set_device_one_partition().  This is in preparation for having an
encrypted file system represented as a Partition object inside a
PartitionLUKS object and needing to call set_mountpoints() for the inner
single Partition object.

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:40 -07:00
Mike Fleetwood 132091269c Implement demand loading of LUKS_Info cache (#760080)
Only load the LUKS_Info cache of active dm-crypt mappings when the first
LUKS partition is encountered.  Not needed from a performance point of
view as the longest that I have ever seen "dmsetup table --target crypt"
take to run is 0.05 seconds.  Just means that the dmsetup command is
only run when there are LUKS partitions and the information is needed.

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:40 -07:00
Mike Fleetwood 317114ffcb Populate LUKS partition usage (#760080)
Populate the used, unused and unallocated figures in the Partition
object for a LUKS formatted partition.  See comment in
luks::set_used_sectors() for the rational of what is used, unused and
unallocated.

As that rational mentions, a LUKS header does not store the size of the
encrypted data and is assumed to extend to the end of the partition by
the tools which start the mapping.

An underlying block device of 128 MiB (131072 KiB).
    # sfdisk -s /dev/sde
    131072

An active LUKS mapping at offset 2 MiB (4096 512-byte sectors) and
length 126 MiB (129024 KiB, 258048 512-byte sectors).
    # sfdisk -s /dev/mapper/sde_crypt
    129024
    # cryptsetup status sde_crypt
    /dev/mapper/sde_crypt is active.
      type:  LUKS1
      cipher:  aes-cbc-essiv:sha256
      keysize: 256 bits
      device:  /dev/sde
      offset:  4096 sectors
      size:    258048 sectors
      mode:    read/write

No size/length reported when dumping the LUKS header, just (payload)
offset.
    # cryptsetup luksDump /dev/sde
    LUKS header information for /dev/sde

    Version:        1
    Cipher name:    aes
    Cipher mode:    cbc-essiv:sha256
    Hash spec:      sha1
    Payload offset: 4096
    MK bits:        256
    MK digest:      7f fb ba 40 7e ba e4 3b 2f c6 d0 93 7b f7 05 49 7b 72 d4 ad
    MK salt:        4a 5b 54 f9 7b 67 af 6e ef 16 31 0a fe d9 7e 5f
                    c3 66 dc 8a ed e0 07 f4 45 c3 7c 1a 8d 7d ac f4
    MK iterations:  37750
    UUID:           0a337705-434a-4994-a842-5b4351cb3778
    ...

Shrink the LUKS mapping to 64 MiB (65536 KiB, 131072 512-byte sectors).
    # cryptsetup resize --size 131072 sde_crypt
    # sfdisk -s /dev/mapper/sde_crypt
    65536
    # cryptsetup status sde_crypt
    /dev/mapper/sde_crypt is active.
      type:  LUKS1
      cipher:  aes-cbc-essiv:sha256
      keysize: 256 bits
      device:  /dev/sde
      offset:  4096 sectors
      size:    131072 sectors
      mode:    read/write

Stop and start the LUKS mapping.
    # cryptsetup luksClose sde_crypt
    # cryptsetup luksOpen /dev/sde sde_crypt

The size of the LUKS mapping is back to 126 MiB (129024 KiB, 258048
512-byte sectors), extending to the end of the partition.
    # sfdisk -s /dev/mapper/sde_crypt
    129024
    # cryptsetup status sde_crypt
    /dev/mapper/sde_crypt is active.
      type:  LUKS1
      cipher:  aes-cbc-essiv:sha256
      keysize: 256 bits
      device:  /dev/sde
      offset:  4096 sectors
      size:    258048 sectors
      mode:    read/write

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:40 -07:00
Mike Fleetwood 317e444056 Add loading of LUKS mapping offset and length (#760080)
Also load the starting offset and length of the active dm-crypt mapping
into the LUKS_Info module from the dmsetup output.  This provides the
location and size of the encrypted data within the underlying block
device.

Note that dmsetup reports in units of 512 bytes sectors [1], the GParted
LUKS_Info module uses bytes and GParted Partition objects work in device
sector size units.  However the actual sector size of a dm-crypt mapping
[2] is the same as that of the underlying block device [3].

    # modprobe scsi_debug dev_size_mb=128 sector_size=4096
    # fgrep scsi_debug /sys/block/*/device/model
    /sys/block/sdd/device/model:scsi_debug
    # parted /dev/sde print
    Error: /dev/sde: unrecognised disk label
    Model: Linux scsi_debug (scsi)
    Disk /dev/sde: 134MB
[3] Sector size (logical/physical): 4096B/4096B
    Partition Table: unknown

    # cryptsetup luksFormat /dev/sde
    # cryptsetup luksOpen /dev/sde sde_crypt
    # parted /dev/mapper/sde_crypt print
    Error: /dev/mapper/sde_crypt: unrecognised disk label
    Model: Linux device-mapper (crypt) (dm)
    Disk /dev/mapper/sde_crypt: 132MB
[2] Sector size (logical/physical): 4096B/4096B
    Partition Table: unknown

    # cryptsetup status sde_crypt
    /dev/mapper/sde_crypt is active.
      type:  LUKS1
      cipher:  aes-cbc-essiv:sha256
      keysize: 256 bits
      device:  /dev/sde
      offset:  4096 sectors
      size:    258048 sectors
      mode:    read/write
    # dmsetup table --target crypt
    ...
    sde_crypt: 0 258048 crypt aes-cbc-essiv:sha256 0000000000000000000000000000000000000000000000000000000000000000 0 8:64 4096

[1] Both cryptsetup and dmsetup report the offset as 4096 and the size/
length as 258048.  128 MiB / (4096+258048) = 512 byte units, even on a
4096 byte sector size device.

Update debugging of LUKS to this:

    # ./gpartedbin
    ======================
    libparted : 2.4
    ======================
    DEBUG: /dev/sdb5: LUKS closed
    DEBUG: /dev/sdb6: LUKS open mapping /dev/mapper/sdb6_crypt, offset=2097152, length=534773760
    /dev/sde: unrecognised disk label
    DEBUG: /dev/sde: LUKS open mapping /dev/mapper/sde_crypt, offset=2097152, length=132120576

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:40 -07:00
Mike Fleetwood 070d734e57 Add busy detection of LUKS mapping (#760080)
Provide a minimal implementation of a luks file system class which only
does busy detection.

NOTE:
For now, read-only LUKS support, a LUKS partition will be busy when a
dm-crypt mapping exists.  Later when read-write LUKS support is added
GParted will need to look at the busy status of the encrypted file
system within the open LUKS partition and map LUKS partition busy status
to encryption being open or closed.

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:40 -07:00
Mike Fleetwood b77a6be76b Add initial loading of LUKS mapping details (#760080)
Load basic details of active Device-mapper encryption mappings from the
kernel.  Use dmsetup active targets.

    # cryptsetup luksFormat /dev/sdb5
    # cryptsetup luksFormat /dev/sdb6
    # cryptsetup luksOpen /dev/sdb6 sdb6_crypt
    # ls -l /dev/mapper/sdb6_crypt /dev/dm-0
    lrwxrwxrwx. 1 root root 7 Nov 15 09:03 /dev/mapper/sdb6_crypt -> ../dm-0
    brw-rw----. 1 root disk 253, 0 Nov 15 09:03 /dev/dm-0
    # ls -l /dev/sdb6
    brw-rw----. 1 root disk 8, 22 Nov 15 09:02 /dev/sdb6
    # dmsetup table --target crypt
    sdb6_crypt: 0 1044480 crypt aes-cbc-essiv:sha256 0000000000000000000000000000000000000000000000000000000000000000 0 8:22 4096

So far just load the mapping name and underlying block device reference
(path or major, minor pair).

Note that all supported kernels appear to report the underlying block
device as major, minor pair in the dmsetup output.  Underlying block
device paths are added to the cache when found during a search to avoid
stat(2) call on subsequent searches for the same path.

Prints debugging to show results, like this:

    # ./gpartedbin
    ======================
    libparted : 2.4
    ======================
    DEBUG: /dev/sdb5: LUKS closed
    DEBUG: /dev/sdb6: LUKS open mapping /dev/mapper/sdb6_crypt

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:40 -07:00
Mike Fleetwood 1b55dfad5b Move DEV_MAPPER_PATH from DMRaid.h to Utils.h (#760080)
Renamed from DEV_MAP_PATH to DEV_MAPPER_PATH.  Moved so that the
constant is logically intended for use outside of the DMRaid class.

Also specifically make the string constant have external linkage, rather
than the default internal (static) linkage for constants, so that there
is only one copy of the variable in the program, rather than one copy in
each compilation unit which included DMRaid.h.  Namely DMRaid.cc and
GParted_Core.cc.

References:
[1] Proper way to do const std::string in a header file?
    http://stackoverflow.com/questions/10201880/proper-way-to-do-const-stdstring-in-a-header-file
[2] What is external linkage and internal linkage in C++
    http://stackoverflow.com/questions/1358400/what-is-external-linkage-and-internal-linkage-in-c/1358796#1358796

Bug 760080 - Implement read-only LUKS support
2016-01-29 13:41:40 -07:00
Mike Fleetwood cd64d6503b Remove unused Partition(path) constructor
History:

1) The constructor was added by commit:

    6d8b169e73
    2006-03-14 21:37:47
    changed the way devices and partitions store their devicepaths.  Instead of

2) Removed from most of the file system specific ::Copy() methods by
   commit:

    ad9f2126e7
    2006-03-19 15:30:20
    fixed issues with copying (see also #335004) cleanups + added FIXME added

3) Removed from GParted_Core::copy() method by commit:

    7bb7e8a84f
    2006-05-23 22:17:34
    Use ped_device_read and ped_device_write instead of 'dd' to copy

4) Finally removed from the last place in xfs::Copy() method by commit:

    e414b71b73
    2012-01-11 19:49:13
    Update xfs resize and copy to use new helper functions

The Partition(path) constructor is no longer used.  Remove.
2016-01-26 10:11:36 -07:00
Mike Fleetwood 561e2203d5 Add virtual qualifier to derived Operation class destructors
When a base class destructor is virtual, derived class destructors are
also virtual [1] even if they don't have the virtual qualifier.

As the Operation destructor is virtual, derived Operation* classes
destructors are virtual too.  Add virtual qualifier just to reflect what
the C++ language mandates the compiler implement.

[1] Derived class with non-virtual destructor
    http://stackoverflow.com/questions/7403883/derived-class-with-non-virtual-destructor
2016-01-26 10:11:36 -07:00
Mike Fleetwood 24fa553385 Remove unnecessary sector_size parameter from Get_New_Partition methods
The sector_size parameter is unnecessary as the value can be retrieved
from the sector size of the selected Partition object on which the
create new, copy & paste or resize/move operation is being performed.

For the create new and resize/move operations it is trivial as the
existing unallocated or in use Partition object on which the operation
is being perform already contains the correct sector size.  For the copy
& paste operation, which can copy across disk devices of different
sector sizes, we merely have to use the sector size of the existing
selected (destination) Partition object rather than copied (source)
Partition object.  Hence these relevant lines in the new code:

    Dialog_Partition_Copy::set_data(selected_partition, copied_partition)
        new_partition = copied_partition.clone();
        ...
        new_partition->sector_size = selected_partition.sector_size;
2016-01-26 10:11:35 -07:00
Mike Fleetwood 1a4cefb960 Initialise all struct FS members
The struct FS constructor initialised every member *except* filesystem
and busy.  Then in *most* cases after declaring struct FS, assignments
followed like this:
    FS fs;
    fs.filesystem = FS_BTRFS;
    fs.busy       = FS::GPARTED;
But member busy wasn't always initialised.

Add initialisation of members filesystem and busy to the struct FS
constructor.  Specify optional parameter to the constructor to set the
filesystem member, or when left off filesystem is initialised to
FS_UNKNOWN.
2016-01-26 10:11:35 -07:00
Mike Fleetwood 320e166c03 Implement and use virtual Partition copy constructor clone() (#759726)
Final step for full polymorphic handling of Partition objects is to
implement a virtual copy constructor.  C++ doesn't directly support
virtual copy constructors, so instead use the virtual copy constructor
idiom [1].  (Just a virtual method called clone() which is implemented
in every polymorphic class and creates a clone of the current object and
returns a pointer to it).

Then replace all calls to the (monomorphic) Partition object copy
constructor throughout the code, except in the clone() implementation
itself, with calls to the new virtual clone() method "virtual copy
constructor".

Also have to make the Partition destructor virtual too [2][3] so that
the derived class destructor is called when deleting using a base class
pointer.  C++ supports this directly.

[1] Wikibooks: More C++ Idioms / Virtual Constructor
    https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Virtual_Constructor

[2] When to use virtual destructors?
    http://stackoverflow.com/questions/461203/when-to-use-virtual-destructors

[3] Virtuality
    Guideline #4: A base class destructor should be either public and
    virtual, or protected and nonvirtual
    http://www.gotw.ca/publications/mill18.htm

Bug 759726 - Implement Partition object polymorphism

SQUASH: When first using pointers to Partition and calling delete
2016-01-26 10:11:35 -07:00
Mike Fleetwood 656e1709ff Replace all Partition object copy assignment (#759726)
Copy assignment of Partition objects is now only performed in a few
places in the Operation and OperationResizeMove classes when updating
the displayed PartitionVector.  (From Refresh_Visual() when each
operation is visually applied to the display_partitions vector; the
new_partition from the operation is copy assigned over the top of the
relevant existing partition in the display_partitions vector).

In general polymorphic copy assignment is complicated [1], and is now
unnecessary given the above limited use.  All that is needed is a way to
polymorphically replace one Partition object with another in a
PartitionVector.

First, prevent further use of Partition object copy assignment by
providing a private declaration and no implementation, so the compiler
enforces this.  Second implement and use PartitionVector method
replace_at() which replaces a pointer to one Partition object with
another at the specified index in the PartitionVector.

[1] The Assignment Operator Revisited
    [Section:] Virtual assignment
    http://icu-project.org/docs/papers/cpp_report/the_assignment_operator_revisited.html

Bug 759726 - Implement Partition object polymorphism
2016-01-26 10:11:35 -07:00
Mike Fleetwood 4a6cbcd0f1 Use pointer to Partition in Dialog_Base_Partition and derived classes (#759726)
Now use a pointer to the Partition object in Dialog_Base_Partition class
and derived classes, Dialog_Partition_{Copy,New,Resize_Move}.  This is
equivalent to how the Partition objects are managed in the Operation and
derived classes.

The Partition object is allocated and copy constructed in each derived
classes' set_data() method, called from each constructor and deallocated
in the destructors.  Considering the remaining Big 3, these classes are
never copy constructed or copy assigned so provide private definitions
and no implementations so the compiler enforces this.

Bug 759726 - Implement Partition object polymorphism
2016-01-26 10:11:35 -07:00
Mike Fleetwood ea8ab702f7 Change copied_partition into a pointer (#759726)
Change Win_GParted::copied_partition from Partition object which is
copied by value into a pointer to a Partition object object which is
allocated, copy constructed and deleted.  Required as part of the
polymorphic implementation of Partitions.

As before when managing the lifetime of pointers to objects in a class
the Big 3 of destructor, copy constructor and copy assignment operator
need to be considered.  A destructor is added to finally delete
copied_partition.  A single Win_GParted object is only ever created and
destroyed in main().  The class is never copy constructed or copy
assigned.  Make the compiler enforce this with private declarations and
no implementations.

Bug 759726 - Implement Partition object polymorphism
2016-01-26 10:11:35 -07:00
Mike Fleetwood b516b1093c Use pointers to Partitions in Operation classes (#759726)
Operation classes now internally use pointers to Partition objects and
take on management of their lifetimes.  As before, with the
PartitionVector class, when storing pointers in a class the Big 3 of
destructor, copy constructor and copy assignment operator also have to
be considered.

First, all the Partition objects are allocated in the derived Operation*
class parameterised constructors and freed in the associated
destructors.  However the Operation classes are never copy constructed
or copy assigned; they are only ever created and destroyed.  Only
pointers to the derived Operations are copied into the vector of pending
operations.  Therefore the copy construtor and copy assignment operator
aren't needed.  To enforce this provide inaccessible private
declarations without any implementation so that the compiler will
enforce this [1][2].

This example code fragment:
 1  OperationCheck o1( device, partition );
 2  OperationCheck o2 = o1;
 3  o2 = o1;
Does these OperationCheck calls:
 1  Implemented parameterised construtor,
 2  Disallowed copy constructor,
 3  Disallowed copy assignment

Trying to compile the above code would fail with errors like these:
    ../include/OperationCheck.h: In member function 'void GParted::Win_GParted::activate_check()':
    ../include/OperationCheck.h:36:2: error: 'GParted::OperationCheck::OperationCheck(const GParted::OperationCheck&)' is private
      OperationCheck( const OperationCheck & src );              // Not implemented copy constructor
      ^
    test.cc:2:21: error: within this context
      OperationCheck o2 = o1;
                          ^

    ../include/OperationCheck.h:37:19: error: 'GParted::OperationCheck& GParted::OperationCheck::operator=(const GParted::OperationCheck&)' is private
      OperationCheck & operator=( const OperationCheck & rhs );  // Not implemented copy assignment operator
                       ^
    test.cc:3:4: error: within this context
      o2 = o1;
         ^

[1] Disable copy constructor
    http://stackoverflow.com/questions/6077143/disable-copy-constructor
[2] Disable compiler-generated copy-assignment operator [duplicate]
    http://stackoverflow.com/questions/7823845/disable-compiler-generated-copy-assignment-operator

Bug 759726 - Implement Partition object polymorphism
2016-01-26 10:11:35 -07:00
Mike Fleetwood 6fd37c0745 Protect partition members within Operation classes (#759726)
The Operation classes contain partition objects which are copied by
value.  Need to replace these with pointers to Partition objects instead
and manage their lifetimes so that they can be used polymorphically.

First step is to protect the partition members partition_new,
partition_original, and for OperationCopy class only, partition_copied
within the Operation classes and provide accessor methods.

get_partition_new() and get_partition_original() accessors are
implemented in the Operation base class so all derived classes get an
implementation.  get_partition_new() is also virtual so that
OperationCheck and OperationDelete can override the implementation and
assert that they don't use partition_new.  get_partition_copied() is
provided for the OperationCopy class only so can only be accessed via an
OperationCopy type variable.

Bug 759726 - Implement Partition object polymorphism
2016-01-26 10:11:35 -07:00
Mike Fleetwood 504a2d8393 Remove copy constructing add item methods from PartitionVector (#759726)
Remove PartitionVector push_back() and insert() methods which copy
construct Partitions objects into the vector.  All the code has already
been changed to dynamically allocate Partition objects and use the
adoption variants of these methods named, push_back_adopt() and
insert_adopt().  Remove the no longer used methods.

Bug 759726 - Implement Partition object polymorphism
2016-01-26 10:11:35 -07:00
Mike Fleetwood 2a2a99b2bf Consolidate down to a single insert_unallocated() implementation (#759726)
GParted_Core and Operation classes both have an insert_unallocated()
method which do the same thing with very nearly identical code.  Both
methods insert unallocated partitions into the vector of partitions
within the specified range of sectors to fill in any gaps larger than
1 MiB.  The only difference was how the two methods got the device path;
the GParted_Core class method got it via a parameter and the Operation
class method got it by calling get_path() on its device member variable.
The GParted_Core insert_unallocated() method gets called during device
scanning and the Operation one gets called when constructing the visual
for a pending operation.

Consolidate down to a single insert_unallocated() implementation by
making the Operation class method call the GParted_Core class method.
Make the GParted_Core class method static and public so that it can be
called using the class name from outside the class.

Bug 759726 - Implement Partition object polymorphism
2016-01-26 10:11:35 -07:00
Mike Fleetwood fdbd86f1ea Add adoption methods for adding items into a PartitionVector (#759726)
The current code uses push_back() and insert() to copy Partition objects
into the vector of pointers.  This has a few issues:
1) Unnecessary copying of Partition objects;
2) Hides the nature of the PartitionVector class as a manager of
   pointers to Partition objects by providing copy semantics to add
   items.  It is generally better to be explicit;
3) C++ doesn't provide polymorphic copy construction directly, but this
   is easily worked around by following the Virtual Constructor idiom
   [1], which would allow PartitionLUKS derived class objects to be
   copied into the vector.

Add push_back_adopt() and insert_adopt() methods which add a pointer to
a Partition object into the PartitionVector adopting ownership.

[1] Wikibooks: More C++ Idioms / Virtual Constructor
    https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Virtual_Constructor

Bug 759726 - Implement Partition object polymorphism
2016-01-26 10:11:35 -07:00
Mike Fleetwood 06b8a3a14a Use pointers to Partitions in PartitionVector class (#759726)
The PartitionVector class is now internally using pointers to Partition
objects and taking on management of their lifetimes.  It therefore has
to implement the Big 3: destructor, copy constructor and copy assignment
operator [1][2].  This is because the implicitly-defined copy
constructor and assignment operator perform memberwise "shallow copying"
and the destructor does nothing.  This not correct for classes which
contain non-class types such as raw pointers.

The semantics of the interface still copies each Partition object into
the PartitionVector when they are added with push_back() and insert().

Note that a PartitionVector object is explicitly copy assigned in
Win_GParted::Refresh_Visual().  They are also implicitly copied when
(1) the implementing vector is resized larger to allow it to hold more
pointers to Partition objects than it previously had capacity for; and
(2) a Partition object is copied including the logicals PartitionVector
member.

[1] The rule of three/five/zero
    http://en.cppreference.com/w/cpp/language/rule_of_three
[2] Rule of Three
    https://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29

Bug 759726 - Implement Partition object polymorphism
2016-01-26 10:11:35 -07:00
Mike Fleetwood 48d898ebfd Include Partition.h header everywhere it's used
Lots of files which use the Partition class relied on the declaration
being included via other header files.  This is bad practice.

Add #include "Partition.h" into every file which uses the Partition
class which doesn't already include it.  Header file #include guards are
specifically to allow this.
2016-01-26 10:11:35 -07:00
Mike Fleetwood fae909897e Use PartitionVector class throughout the code (#759726)
Replace all occurrences of std::vector<Partition> with PartitionVector.

Bug 759726 - Implement Partition object polymorphism
2016-01-26 10:11:35 -07:00
Mike Fleetwood 81337141d7 Stop returning vector of partitions from Dialog_Rescue_Data class (#759726)
get_partitions() method was returning a vector of partitions.  However
the calling code only needed to know whether any partitions were found
or not.  Replace with found_partitions() method reporting the needed
boolean.

Now use of std::vector<Partition> partitions is hidden within the
Dialog_Rescue_Data class implementation.

Bug 759726 - Implement Partition object polymorphism
2016-01-26 10:11:34 -07:00
Mike Fleetwood fa98273445 Create PartitionVector class (#759726)
Just creates PartitionVector class and includes it in partition.h so
that it is built and validated by the compiler.  Not used anywhere yet.

Implementation strategy is to create a PartitionLUKS class derived from
the Partition class.  This implies polymorphism of Partition objects,
which in C++ requires using pointers and references to objects, and not
using objects directly.  (See C++ object slicing).  Later this
PartitionVector class will be modified to use pointers to Partition
objects and act as the owner of the pointed to Partition objects.

Bug 759726 - Implement Partition object polymorphism
2016-01-26 10:11:34 -07:00
Phillip Susi ae434579e1 Display progress for e2fsck (#467925)
Parse output and update progress bar.

Bug 467925 - gparted: add progress bar during operation
2015-12-14 10:42:04 -07:00
Phillip Susi baea186138 Display progress for mke2fs (#467925)
Bug 467925 - gparted: add progress bar during operation
2015-12-14 10:42:04 -07:00
Phillip Susi 57b028bb8e Display progress during resize (#467925)
Capture and parse the progress reports of ntfsresize and resize2fs and
update the dialog progress bar.

Bug 467925 - gparted: add progress bar during operation
2015-12-14 10:42:04 -07:00
Mike Fleetwood 2c4df87a2c Return reference from Get_New_Partition() (#757671)
Return newly constructed partition object by reference rather than by
copy from the Copy, Resize/Move and New dialog classes.  This is another
case of stopping copying partition objects in preparation for using
polymorphic Partition objects.  In C++ polymorphism has to use pass by
pointer and reference and not pass by value, copying, to avoid object
slicing.

The returned reference to the partition is only valid until the dialog
object containing the new_partition member is destroyed.  This is okay
because in all three cases the returned referenced partition is copied
into a context with new lifetime expectations before the dialog object
is destroyed.

Case 1: GParted_Core::activate_paste()
    Referenced new_partition is copied in the OperationCopy constructor
    before the dialog object goes out of scope.

    Operation * operation = new OperationCopy( ...,
                                               dialog.Get_New_Partition( ... ),
                                               ... );

Case 2: GParted_Core::activate_new()
    Referenced new_partition is copied in the OperationCreate
    constructor before the dialog object goes out of scope.

    Operation * operation = new OperationCreate( ...,
                                                 dialog.Get_New_Partition( ... ) );

Case 3: GParted_Core::activate_resize()
    Temporary partition object is copied from the referenced
    new_partition before the dialog object goes out of scope.

    Partition part_temp = dialog.Get_New_Partition( ... );

Bug 757671 - Rework Dialog_Partition_New::Get_New_Partition() a bit
2015-11-11 10:12:18 -07:00
Mike Fleetwood 451c2eac43 Rename parameter to selected_partition in Dialog_Partition_New methods (#757671)
This is just to make the parameter name in the Dialog_Partition_New
constructor and set_data() method match the name of the equivalent
parameter in the Dialog_Partition_Copy and Dialog_Partition_Resize_Move
classes.  (All three classes inherit from Dialog_Base_Partition and have
similar interfaces).

Bug 757671 - Rework Dialog_Partition_New::Get_New_Partition() a bit
2015-11-11 10:12:18 -07:00
Mike Fleetwood bab1109d3d Ensure SWRaid_Info cache is loaded at least once (#756829)
Automatically load the cache of SWRaid information for the first time if
any of the querying methods are called before the first explicit
load_cache() call.  Means we can't accidentally use the class and
incorrectly find no SWRaid members when they do exist.

Bug 756829 - SWRaid member detection enhancements
2015-11-02 10:03:45 -07:00
Mike Fleetwood f6c2f00df7 Populate member mount point with SWRaid array device (#756829)
Busy file systems are accessed via a mount point, LVM Physical Volumes
are activated via the Volume Group name and busy SWRaid members are
accessed via the array device, /dev entry.  Therefore choose to show the
array device in the mount point field for busy SWRaid members.

The kernel device name for an SWRaid array (without leading "/dev/") is
the same as used in /proc/mdstat and /proc/partitions.  Therefore the
array device (with leading "/dev/") displayed in GParted will match
between the mount point for busy SWRaid members and the array itself as
used in the device combo box.

    # cat /proc/mdstat
    Personalities : [raid1]
    md1 : active raid1 sda1[2] sdb1[3]
          524224 blocks super 1.0 [2/2] [UU]
    ...
    # cat /proc/partitions
    major minor  #blocks  name

       8        0   33554432 sda
       8        1     524288 sda1
    ...
       8       16   33554432 sdb
       8       17     524288 sdb1
    ...
       9        1     524224 md1
    ...

Bug 756829 - SWRaid member detection enhancements
2015-11-02 10:03:45 -07:00
Mike Fleetwood 7255c8af40 Use UUID and label of SWRaid arrays too (#756829)
In cases where blkid wrongly reports a file system instead of an SWRaid
member (sometimes confused by metadata 0.90/1.0 mirror array or old
version not recognising SWRaid members), the UUID and label are
obviously wrong too.  Therefore have to use the UUID and label returned
by the mdadm query command and never anything reported by blkid or any
file system specific command.

Example of blkid reporting the wrong type, UUID and label for /dev/sda1
and the correct values for /dev/sdb1:

    # blkid | egrep 'sd[ab]1'
    /dev/sda1: UUID="10ab5f7d-7d8a-4171-8b6a-5e973b402501" TYPE="ext4" LABEL="chimney-boot"
    /dev/sdb1: UUID="15224a42-c25b-bcd9-15db-60004e5fe53a" UUID_SUB="0a095e45-9360-1b17-0ad1-1fe369e22b98" LABEL="chimney:1" TYPE="linux_raid_member"

    # mdadm -E -s -v
    ARRAY /dev/md/1  level=raid1 metadata=1.0 num-devices=2 UUID=15224a42:c25bbcd9:15db6000:4e5fe53a name=chimney:1
       devices=/dev/sda1,/dev/sdb1
    ...
    ARRAY /dev/md127 level=raid1 num-devices=2 UUID=8dc7483c:d74ee0a8:b6a8dc3c:a57e43f8
       devices=/dev/sdb6,/dev/sda6
    ...

NOTES:
* In mdadm terminology the label is called the array name, hence name=
  parameter for array md/1 in the above output.
* Metadata 0.90 arrays don't support naming, hence the missing name=
  parameter for array md127 in the above output.

Bug 756829 - SWRaid member detection enhancements
2015-11-02 10:03:45 -07:00
Mike Fleetwood 0ce9857380 Move busy detection of SWRaid members into the new module (#756829)
Add active attribute to the cache of SWRaid members.  Move parsing of
/proc/mdstat to discover busy SWRaid members into the cache loading
code.  New parsing code is a little different because it is finding all
members of active arrays rather than determining if a specific member is
active.

Bug 756829 - SWRaid member detection enhancements
2015-11-02 10:03:45 -07:00
Mike Fleetwood 5f02bcf463 Detect Linux SWRaid members by querying mdadm (#756829)
Detection of Linux SWRaid members currently fails in a number of cases:

1)  Arrays which use metadata type 0.90 or 1.0 store the super block at
    the end of the partition.  So file system signatures in at least
    linear and mirrored arrays occur at the same offsets in the
    underlying partitions.  As libparted only recognises file systems
    this is what is detected, rather than an SWRaid member.

    # mdadm -E -s -v
    ARRAY /dev/md/1  level=raid1 metadata=1.0 num-devices=2 UUID=15224a42:c25bbcd9:15db6000:4e5fe53a name=chimney:1
       devices=/dev/sda1,/dev/sdb1
    ...
    # wipefs /dev/sda1
    offset               type
    ----------------------------------------------------------------
    0x438                ext4   [filesystem]
                         LABEL: chimney-boot
                         UUID:  10ab5f7d-7d8a-4171-8b6a-5e973b402501

    0x1fffe000           linux_raid_member   [raid]
                         LABEL: chimney:1
                         UUID:  15224a42-c25b-bcd9-15db-60004e5fe53a

    # parted /dev/sda print
    Model: ATA VBOX HARDDISK (scsi)
    Disk /dev/sda: 34.4GB
    Sector size (logical/physical): 512B/512B
    Partition Table: msdos

    Number  Start   End     Size    Type      File system  Flags
     1      1049kB  538MB   537MB   primary   ext4         boot, raid
    ...

2)  Again with metadata type 0.90 or 1.0 arrays blkid may report the
    contained file system instead of an SWRaid member.  Have a single
    example of this configuration with a mirrored array containing the
    /boot file system.  Blkid reports one member as ext4 and the other as
    SWRaid!

    # blkid | egrep 'sd[ab]1'
    /dev/sda1: UUID="10ab5f7d-7d8a-4171-8b6a-5e973b402501" TYPE="ext4" LABEL="chimney-boot"
    /dev/sdb1: UUID="15224a42-c25b-bcd9-15db-60004e5fe53a" UUID_SUB="0a095e45-9360-1b17-0ad1-1fe369e22b98" LABEL="chimney:1" TYPE="linux_raid_member"

    Bypassing the blkid cache gets the correct result.

    # blkid -c /dev/null /dev/sda1
    /dev/sda1: UUID="15224a42-c25b-bcd9-15db-60004e5fe53a" UUID_SUB="d0460f90-d11a-e80a-ee1c-3d104dae7e5d" LABEL="chimney:1" TYPE="linux_raid_member"

    However this can't be used because if a user has a floppy configured
    in the BIOS but no floppy attached, GParted will wait for minutes as
    the kernel tries to access non-existent hardware on behalf of the
    blkid query.  See commit:
        18f863151c
        Fix long scan problem when BIOS floppy setting incorrect

3)  Old versions of blkid don't recognise SWRaid members at all so always
    report the file system when found.  Occurs with blkid v1.0 on
    RedHat / CentOS 5.

The only way I can see how to fix all these cases is to use the mdadm
command to query the configured arrays.  Then use this information for
first choice when detecting partition content, making the order: SWRaid
members, libparted, blkid and internal.

GParted shell wrapper already creates temporary blank udev rules to
prevent Linux Software RAID arrays being automatically started when
GParted refreshes its device information[1].  However an administrator
could manually stop or start arrays or change their configuration
between refreshes so GParted must load this information every refresh.
On my desktop with 4 internal hard drives and 3 testing Linux Software
RAID arrays, running mdadm adds between 0.20 and 0.30 seconds to the
device refresh time.

[1] a255abf343
    Prevent GParted starting stopped Linux Software RAID arrays (#709640)

Bug 756829 - SWRaid member detection enhancements
2015-11-02 10:03:45 -07:00
Mike Fleetwood 037020b116 Create new method GParted_Core::useable_device() (#755495)
Abstract code checking sector size and ensuring the first sector of a
candidate disk device can be read into new
GParted_Core::useable_device() method.

Bug 755495 - GParted allowing partitioning of large sector devices
             specified on the command line, when built with old
             libparted which doesn't support it
2015-10-08 13:00:01 -06:00
Mike Fleetwood d925bd2bb5 Stop including removed <sigc++/class_slot.h> header (#756035)
Libsigc++2 version 2.5.2 and later removed header file
<sigc++/class_slot.h>.  Quoting the NEWS file for version 2.5.2:

    Remove useless headers: sigc++/class_slot.h ...

Libsigc++2 version 2.5.2 NEWS file:
https://git.gnome.org/browse/libsigc++2/tree/NEWS?id=2.5.2

Bug 756035 - GParted does not compile with newer gtkmm libraries in
             Fedora 23
2015-10-05 10:14:35 -06:00
Albert Young 584137b32b Remove prohibited characters from FAT16/32 labels (#755608)
GParted waits forever when attempting to set a FAT16/32 file system
label which contains prohibited characters [1][2].  This is because
mlabel asks a question and is waiting for input.  Force cancelling the
operation doesn't work either as GParted sends signal 2 (interrupt i.e.
[Ctrl-C]) but mtools commands specifically ignores this and a number of
other signals.  Have to kill mlabel with signal 9 (kill) to regain
control of GParted.

Mlabel command with prohibited characters in the label:

    # export MTOOLS_SKIP_CHECK=1
    # mlabel ::"MYLABEL/   " -i /dev/sdb10
    Long file name "MYLABEL/   " contains illegal character(s).
    a)utorename A)utorename-all r)ename R)ename-all
    s)kip S)kip-all q)uit (aArRsSq):

Remove prohibited characters from FAT16/32 file systems labels when
creating and labelling them.  Also upper case the label to meet label
requirements [1][2].  This silently corrects the label and the actual
label applied will be displayed when GParted refreshes after applying
the operation.

[1] Microsoft TechNet: Label
    https://technet.microsoft.com/en-us/library/bb490925.aspx

[2] Replicated in Wikikedia: label (command)
    https://en.wikipedia.org/wiki/Label_%28command%29

Bug 755608 - Labeling fat16/fat32 partitions hangs if certain characters
             included in label
2015-10-04 09:57:07 -06:00
Mike Fleetwood cbfb7e51f5 Replace Operation class members index and index_extended with local variables (#755214)
These member variables store no Operation class information and were
being used as local variables.  Replace with local variables.

Also indent a code block within an if clause so that the compiler can
confirm that the new local variable isn't used uninitialised.  Prevents
this compiler warning:
    OperationResizeMove.cc: In member function 'void GParted::OperationResizeMove::apply_normal_to_visual(std::vector<GParted::Partition, std::allocator<GParted::Partition> >&)':
    OperationResizeMove.cc:125: warning: 'index' may be used uninitialized in this function

Bug 755214 - Refactor operation merging
2015-09-28 11:02:07 -06:00
Mike Fleetwood a1ab21285b Remove unused index parameter from Add_Operation() (#755214)
Since this commit earlier in the patchset the second optional parameter
of method Win_GParted::Add_Operation() is no longer used.  Remove it.
    Replace open coded merge of resize/move into create operation
    (#755214)

Bug 755214 - Refactor operation merging
2015-09-28 11:02:07 -06:00
Mike Fleetwood dc6ffc6a87 Move code visually re-applying create operation into parent class (#755214)
Move the code from OperationCreate::apply_to_visual() into new method
Operation::insert_new() in the parent class.  This is in preparation for
the following commit.

Bug 755214 - Refactor operation merging
2015-09-28 10:41:39 -06:00
Mike Fleetwood 27cbe36d0f Share duplicate code substituting partitions in multiple operations (#755214)
The apply_to_visual() method for the change UUID, format, label file
system and name partition operations duplicated identical code.  This
code was just substituting the partition in the disk graphic vector with
the new partition recorded in the operation, as none of these operations
change the partition boundaries.  Move this duplicate code into the
parent class in new method Operation::substitute_new().

Bug 755214 - Refactor operation merging
2015-09-28 10:41:39 -06:00
Mike Fleetwood 9b497aae14 Fix visually re-applying create operation in create-create-grow-first sequence (#755214)
After previous commit "Replace open coded merge of resize/move into
create operation (#755214)" the second created partition would disappear
from the disk graphic in the following sequence: create new #1, create
new #2 leaving space preceding, resize #1 larger.  The create new #2
operation still existed and was shown in the operation list.  It was
just that it disappeared from the disk graphic.

Remember that when each operation is created it records the partition,
or the unallocated space, to which the operation is applied at the time
the operation is created in the partition_original member variable.  In
the above sequence the resize #1 larger operation was merged back into
the create new #1 operation.  When visually re-applying the create
new #1 operation to the disk graphic, it left a smaller unallocated
partition following it.  This was smaller than the unallocated partition
recorded in the create new #2 operation, hence it failed to visually
re-apply to the disk graphic.

The insight to fix this is that it doesn't matter what size the
unallocated space was when the create new operation was constructed.  It
only matters that the new partition to be created fits in the available
unallocated space currently in the disk graphic.

Bug 755214 - Refactor operation merging
2015-09-28 10:41:39 -06:00
Mike Fleetwood cf5d8d928c Refactor merging rules into new merge_operations() (#755214)
Creation of the various operations involved various implicit rules about
how the different types of operations were merged in different cases.
This was open coded in each ::activate_*() method.  Abstract this into
new merge_operations() method and make the merging rules explicitly
specified.

NOTE:
The removal of operation type checking in the MERGE_LAST_WITH_ANY cases
is not a problem because all the Operation*::merge_operations() methods
ensure the operation types match as part of the merge attempt.

Bug 755214 - Refactor operation merging
2015-09-28 10:41:39 -06:00
Mike Fleetwood d93d8abcc4 Rename function to merge_two_operations() and update validation (#755214)
Rename Win_GParted::Merge_Operations() to merge_two_operations().  To
reflect what it does and in preparation for further refactoring of the
code.

Be more strict on the validation of the first and second indexes.  The
first operation must also be before the second operation in the
operation[] vector.  (It is actually a programming bug if first and
second fail validation.  However so far g_assert() is only being used to
validate pointers, which if wrong would likely cause the program to
eventually crash when dereferenced later.  In this case a bug would
merely cause the incorrectly specified pair of operations to not be
merged).

Move validate_display_partition_ptr() declaration in the header file to
be in the same ordering as it's definition in the source file.

Bug 755214 - Refactor operation merging
2015-09-28 10:41:39 -06:00
Mike Fleetwood 7f4ffd28d5 Encapsulate operation merging inside the Operation* classes (#755214)
Win_GParted::Merge_Operations() method was modifying the internals of
Operation* objects; in particular the partition_new member variable.
This is breaking data hiding and encapsulation tenant of object oriented
programming.

Implement exactly the same operation merge semantics, but hide the
manipulation of the internals of the Operation* objects within the
Operation* classes themselves.

Bug 755214 - Refactor operation merging
2015-09-28 10:41:39 -06:00
Mike Fleetwood 26dc3dffa7 Localise checking for an extended partition into activate_new()
As previous commit, display_partitions is now a Win_GParted member
variable so checking for the existence of an extended partition can be
localised where it is used.

Remove index_extended member variable and localise the same checking in
activate_new().
2015-09-22 09:50:11 -06:00
Mike Fleetwood 3b5471516c Localise counting of primary partitions into max_amount_prim_reached()
Now that display_partitions is a Win_GParted member variable and
therefore available throughout the class, since commit [1], calculation
of primary_count can be localised in max_amount_prim_reached() where it
is used.

Implements a FIXME and removes primary_count as a member variable.

[1] 545b75d957
    Move vector of partition objects to a Win_GParted class member (#750168)
2015-09-22 09:50:11 -06:00
Mike Fleetwood 0e32d39189 Remove unused public member variable FileSystem::success
Assume accidentally added in commit:
    52a2a9b00a
    Reduce threading (#685740)
2015-09-21 10:11:19 -06:00
Mike Fleetwood 2b57229fc2 Implement shell style exit status decoding (#754684)
Command exit status is a 1 byte value between 0 and 255. [1][2]  However
at the Unix API level the value is encoded as documented in the
waitpid(2) manual page.  This is true for the Glib API too. [3]  This is
why, for example, the comment in ext2::check_repair() reported receiving
undocumented exit status 256.  It was actually receiving exit status 1
encoded as per the waitpid(2) method.

Add shell style exit status decoding [2] to execution of all external
commands.   Return value from Utils::execute_command() and
FileSystem::execute_command() functions are now:
    0 - 125 - Exit status from the command
    126     - Error executing the command
    127     - Command not found
    128+N   - Command terminated by signal N
    255     - Unexpected waitpid(2) condition
Also adjust checking of the returned statuses as necessary.

[1] Advanced Bash-Scripting Guide: Appendix D. Exit Codes With Special
    Meanings
    http://www.linuxtopia.org/online_books/advanced_bash_scripting_guide/exitcodes.html

[2] Quote from the bash(1) manual page:

        EXIT STATUS
            ... Exit statuses fall between 0 and 255, though as
            explained below, the shell may use values above 125
            specially.  ...

            ... When a command terminates on a fatal signal N, bash uses
            the value of 128+N as the exit status.

            If a command is not found, the child process created to
            execute it returns a status of 127.  If a command is found
            but is not executable, the return status is 126.

[3] Quote from the Glib Reference Manual, Spawning Processes section,
    for function g_spawn_check_exit_status():
    https://developer.gnome.org/glib/stable/glib-Spawning-Processes.html#g-spawn-check-exit-status

        The g_spawn_sync() and g_child_watch_add() family of APIs return
        an exit status for subprocesses encoded in a platform-specific
        way.  On Unix, this is guaranteed to be in the same format
        waitpid() returns, ...

Bug 754684 - Updates to FileSystem:: and Utils::execute_command()
             functions
2015-09-21 10:11:19 -06:00
Mike Fleetwood 3eccd01f42 Time and check nearly all file system action commands (#754684)
There has been an undocumented rule that external commands displayed in
the operation details, as part of file system manipulations, only get a
time and check mark displayed when multiple commands are needed, and not
otherwise.  (GParted checks whether all commands are successful or not
regardless of whether a check mark is displayed in the operation details
or not).

EXCEPTION 1: btrfs resize

Since the following commit [1] from 2013-02-22, GParted stopped
displaying the timing for the btrfs resize command in the operation
details.  It being part of a multi-command sequence to perform the step.
This is because FileSystem::execute_command() since the commit can only
check the exit status for zero / non-zero while timing and checking the
command status but btrfs resize needs to consider some non-zero statuses
as successful.

[1] 52a2a9b00a
    Reduce threading (#685740)

EXCEPTION 2: ext2/3/4 move and copy using e2image

When use of e2image was added [2] the single command steps were timed
and check.

[2] 86111fe12a
    Use e2image to move/copy ext[234] file systems (#721516)

EXCEPTION 3: fat16/32 write label and UUID

Uses Utils::execute_command() rather than FileSystem::execute_command()
so can be separately changed.  See the following commit for resolution
of the final commands not yet timed and check mark displayed.

CHANGE:

Lets make a simpler rule of always displaying the time and a check mark
for all external commands displayed in the operation details.  However
this makes several of the other single command actions need special exit
status handling because zero success, non-zero failure is not correct
for every case.  Specifically affects resizing of reiserfs and check
repair of ext2/3/4, fat16/32, jfs and reiserfs.

After this change all external commands run as file system actions must
follow one of these two patterns of using the EXEC_CHECK_STATUS flag or
separately calling FileSystem::set_status() to register success or
failure of the command:
    exit_status = execute_command(cmd, od, EXEC_CHECK_STATUS...);
or:
    exit_status = execute_command(cmd, od, ...);
    bool success = (exit_status == 0 || exit_status == OTHER_SUCCESS_VALUE...);
    set_status(od, success );

Bug 754684 - Updates to FileSystem:: and Utils::execute_command()
             functions
2015-09-21 10:11:19 -06:00
Mike Fleetwood 83ecae4918 Refactor flags in method FileSystem::execute_command() (#754684)
Change the two optional boolean parameters into a single optional flags
parameter which uses symbolically defined names.  Makes reading the
execute_command() calls much easier to understand.  (Implemented as bit
field using the same technique as used for Glib::SpawnFlags [1]).

This changes the calls thus:

  execute_command(cmd, od)              -> (cmd, od)
  execute_command(cmd, od, false)       -> (cmd, od, EXEC_NONE)  // [2]
  execute_command(cmd, od, true )       -> (cmd, od, EXEC_CHECK_STATUS)
  execute_command(cmd, od, false, true) -> (cmd, od, EXEC_CANCEL_SAFE)
  execute_command(cmd, od, true , true) ->
                          (cmd, od, EXEC_CHECK_STATUS|EXEC_CANCEL_SAFE)

[1] SpawnFlags bitwise operators in
    /usr/include/glibmm-2.4/glibmm/spawn.h.

[2] False and EXEC_NONE are the default values for the optional third
    parameter before and after this change respectively and both mean
    the same.  This is being used in btrfs::resize() and being kept for
    now despite it being the default.

Bug 754684 - Updates to FileSystem:: and Utils::execute_command()
             functions
2015-09-21 10:11:19 -06:00
Mike Fleetwood d3e17f4484 Remove unused execute_command_timed() (#754684)
Use of execute_command_timed() was removed by this commit from
2013-02-22:
    52a2a9b00a
    Reduce threading (#685740)

Bug 754684 - Updates to FileSystem:: and Utils::execute_command()
             functions
2015-09-21 10:11:19 -06:00
Wrolf Courtney 9e950e89b4 Display list of Logical Volumes in the Partition Information dialog (754649)
Bug 754649 - Display Logical Volumes in Volume Group of LVM2 Partition
2015-09-15 20:12:12 +01:00
Mike Fleetwood 71715a1c29 Add detection of ZFS (#752862)
Requires blkid from util-linux >= 2.15, released May 2009, for
detection of ZFS.

Bug 752862 - ZFS is not recognised
2015-08-08 09:55:42 -06:00
Curtis Gedak 1561d1ae7e Add libparted ped_file_system_resize thread to avoid blocking GUI (#737022)
Since GParted commit 52a2a9b "Reduce threading (#685740)", released in
GParted 0.15.0, application of operations occurs in the main thread
running the UI, therefore long running libparted actions such as
resizing a FAT16 or FAT32 file system hang the UI for as long as it take
to complete the operation.
https://git.gnome.org/browse/gparted/commit/?id=52a2a9b00a32996921ace055e71d0e09fb33c5fe

Though this problem exists for all libparted actions, it is particularly
noticeable when performing a large resize of fat16/fat32/hfs/hfs+ file
systems.

To address this significant cause of an unresponsive GUI, this
enhancement adds threading to the libparted ped_file_system_resize
function call.

Bug 737022 - UI hangs while running libparted operations such as
             FAT16/FAT32 resizing
2015-07-19 21:57:17 +01:00
Mike Fleetwood 54d0e3d056 Remember result of searching the PATH for the hdparm command (#751251)
Previously on every refresh for every device, GParted was searching the
PATH to discover if the hdparm command existed.  Stracing GParted showed
that calling Glib::find_program_in_path("hdparm") made the following OS
calls:
    access("/usr/lib64/qt-3.3/bin/hdparm", X_OK) = -1 ENOENT (No such file or directory)
    access("/usr/local/sbin/hdparm", X_OK) = -1 ENOENT (No such file or directory)
    access("/usr/local/bin/hdparm", X_OK) = -1 ENOENT (No such file or directory)
    access("/sbin/hdparm", X_OK) = 0
    getuid()                    = 0
    stat("/sbin/hdparm", {st_mode=S_IFREG|0755, st_size=137, ...}) = 0
    stat("/sbin/hdparm", {st_mode=S_IFREG|0755, st_size=137, ...}) = 0

The Linux VFS is very fast but repeatedly doing this is wasteful.
Remember the result of searching the PATH for the hdparm command at
startup and refresh this when the [Rescan For Supported Actions] button
is pressed in the File System Support dialog.  This is the same as
GParted already does for file system specific commands and their
capabilities.

Bug 751251 - Show serial number in device information
2015-07-01 10:22:57 -06:00
Mike Fleetwood 4b72ecd44e Display device serial numbers (#751251)
Run "hdparm -I /dev/DISK" to get the hard drive serial number of
every device which has one and display it in the Device Information.
The displayed value can either be the actual serial number, "none" or
blank.  "none" means the device doesn't have a hard drive serial number,
such as for Linux software RAID arrays, BIOS fake RAID arrays or USB
flash drives.  Blank means something went wrong getting the serial
number.  Either it couldn't be found in the hdparm output or the hdparm
command wasn't installed.

Example real hard drive:
    # hdparm -I /dev/sda
    ...
    ATA device, with non-removable media
            Model Number:       SAMSUNG HM500JI
            Serial Number:      S1WFJDSZ123732
    ...

Example Linux software RAID array:
    # hdparm -I /dev/md127

    /dev/md127:
     HDIO_DRIVE_CMD(identify) failed: Inappropriate ioctl for device

On my desktop with 4 internal hard drives 2 Linux software RAID arrays
on those hard drives, 2 USB flash drives and 1 USB hard drive attached,
running hdparm 9 times added 0.07 seconds to the device refresh time.

Bug 751251 - Show serial number in device information
2015-07-01 10:22:47 -06:00
Mike Fleetwood 8308ee6051 Support changing the UUID of a btrfs file system (#751337)
Btrfs-progs 4.1, released June 2015, includes support for changing the
UUID of a btrfs file system using the btrfstune command.  Check for
availability by looking for the -u option in the btrfstune help output.
Use btrfstune like this:

    # umount /dev/sdb1
    # btrfstune -f -u /dev/sdb1
    Current fsid: e7ad5dba-d721-4f99-990b-1ba2901c8ad2
    New fsid: 231563d9-e173-410d-b1da-d34c4319a423
    Set superblock flag CHANGING_FSID
    Change fsid in extents
    Change fsid on devices
    Clear superblock flag CHANGING_FSID
    Fsid change finished
    # echo $?
    0

Bug 751337 - btrfstune in btrfs-progs 4.1 supports changing the file
             system UUID
2015-06-28 10:57:58 -06:00
Mike Fleetwood 9be8d37600 Delay loading LVM2_PV_info cache until actually needed (#750582)
The lvm query commands were always run and the cache loaded even if
GParted, actually blkid, didn't identify any LVM2 PVs.  (GParted uses
libparted and blkid to identify partition content and the lvm commands
to provide the needed configuration details).

Now implement complete lazy initialization of the cache.  Never force
loading of the cache.  The cache is only loaded when the first value is
accessed from it.  When there are no LVM2 PVs, the cache is never
queried, so never loaded.  All the needed infrastructure for delayed
loading was previously added by this commit from 2011-12-11:
    ff8ad04120
    Lazy initialize the cache from querying LVM2 PVs (#160787)
Every public member function which access values from the cache already
calls initialize_if_required().  Just need to replace force loading of
the cache with a function which just clears the cache.

On my desktop, only when there are no LVM2 PVs, not loading the cache
and therefore not executing these external commands in
load_lvm2_pv_info_cache() saves 1.0 seconds of the 3.7 seconds it takes
to perform the a refresh in GParted:
    lvm vgscan
    lvm pvs ... -o pv_name,...
    lvm pvs ... -o vg_name,...

Bug 750582 - Refactor the LVM2_PV_Info module object interface and
             internal cache representation
2015-06-13 10:56:31 -06:00
Mike Fleetwood e6f7ea01f9 Parse LVM2_PV_Info cache into fields while loading (#750582)
GParted used to cache the results of the "lvm pvs" commands used to query
the state of the Logical Volume Manager as a series of lines of text.
Then every time a particular value was queried GParted would split all
the lines of text into fields until the required value was found.

Stop this repeat splitting of cached lines of text.  Instead parse the
lines of text into separate fields and store in structures of values of
the correct type in the cache.

Bug 750582 - Refactor the LVM2_PV_Info module object interface and
             internal cache representation
2015-06-13 10:56:15 -06:00
Mike Fleetwood 2c5e7b0d90 Stop needing any LVM2_PV_Info objects (#750582)
The LVM2_PV_Info cache had a pretend multi-object interface, yet all the
data is static.  An LVM2_PV_Info object doesn't contain any member
variables, yet was needed just to call the member functions.

Make all the member functions static removing the need to use any
LVM2_PV_Info objects.

Bug 750582 - Refactor the LVM2_PV_Info module object interface and
             internal cache representation
2015-06-13 10:56:12 -06:00
Mike Fleetwood 81f0b934bc Stop borrowing the constructor to load the LVM2_PV_Info cache (#750582)
An LVM2_PV_Info object contains no member variables as all the data is
static (exists once in the program and accessed by all objects).  The
constructor did nothing, except when passed true to load the cache.

Provide a separate load_cache() member function and remove the
constructors and destructor which do nothing.  The C++ compiler will
provide a default constructor and destructor, which don't do anything as
there are no member variables to initialise and finalise.

This makes the interface a little easier to understand.  Mostly a step
along the way of refactoring how the LVM2_PV_Info cache module works.

Bug 750582 - Refactor the LVM2_PV_Info module object interface and
             internal cache representation
2015-06-13 10:55:48 -06:00
Mike Fleetwood 7a4a375ed6 Remove Set_Data() from the copy, resize/move and new dialog class APIs
The copy, resize/move and new dialog classes (Dialog_Partition_Copy,
Dialog_Partition_Resize_Move and Dialog_Partition_New respectively) had
to be used like this:

    construct dialog object passing some parameters
    call Set_Data() to pass more parameters
    run() dialog
    call Get_New_Partition()

There is nothing in the classes which forces Set_Data() to be called,
but it must be called for the dialogs to work and prevent GParted from
crashing.

Make these class APIs safer by making it impossible to program
incorrectly in this regard.  Move all the additional parameters from
each Set_Data() method to each constructor.  The constructors just call
the now private set_data() methods.
2015-06-10 10:44:33 -06:00
Mike Fleetwood 32a5ace156 Rename Dialog_Base_Partition member to new_partition
The member variable was named selected_partition.  It is assigned from
Win_GParted::selected_partition_ptr (which is a pointer to a const
partition object so is never updated).  This gives connotations that it
won't be modified.

However it is updated freely as the new resultant partition object is
prepared before being returned from the dialog, most notable in the
Get_New_Partition() methods.

Therefore rename from selected_partition to new_partition.
2015-06-10 10:44:33 -06:00
Mike Fleetwood 8b96f8409f Stop copying selected_partition back on itself in the copy dialog (#750168)
The code goes like this:

    Dialog_Partition_Copy::Get_New_Partition()
        call Dialog_Base_Partition::Get_New_Partition()
            Update this->selected_partition with results from running
            the dialog.
            return this->selected_partition by value.
        Save value back to this->selected_partition.
        Update this->selected_partition some more.
        return this->selected_partition by value.

So there is an unnecessary copy of the partition object returned from
the base class Get_New_Partition() function back to the same variable in
the derived copy class Get_New_Partition() function.

Need to keep the base class Get_New_Partition() function as derived
class Dialog_Partition_Resize_Move uses that implementation as it
doesn't override it, and it's part of the interface.

Avoid this unnecessary copy by moving base class Get_New_Partition()
code into a new private function, called prepare_new_partition(), which
doesn't return anything.  Then have Get_New_Partition() in both classes
just return the required partition object.  Like this:

    Dialog_Base_Partition::Get_New_Partition()
        call prepare_new_partition()
        return this->selected_partition by value.

    Dialog_Partition_Copy::Get_New_Partition()
        call Dialog_Base_Partition::prepare_new_partition()
        Update this->selected_partition some more.
        return this->selected_partition by value.

Bug 750168 - Reduce the amount of copying of partition objects
2015-06-10 10:44:33 -06:00
Mike Fleetwood 90e3ed68fc Shallow copy Device object into Operation object (#750168)
When Operation objects are created they take a copy of the Device object
to which the operation is to be applied.  The Device object includes a
vector of all the contained Partition objects currently on the device,
so these get copied too.

These additional deep copied Partition objects in the Operation object
are never accessed.  Therefore don't copy the contained Partition
objects when copying the Device object into the Operation object.

Bug 750168 - Reduce the amount of copying of partition objects
2015-06-10 10:44:33 -06:00
Mike Fleetwood ece945685c Stop copying selected partition object in Manage Flags dialog (#750168)
When opening the Manage Flags dialog, creation of the dialog object was
creating a copy of the selected partition object.  If this was an
extended partition it also included recursively constructing the
contained logical partitions too.

Instead, replace the partition object in the DialogManageFlags class
with a reference to it.

Bug 750168 - Reduce the amount of copying of partition objects
2015-06-10 10:44:33 -06:00
Mike Fleetwood efaea94301 Stop copying selected partition object in Information dialog (#750168)
When opening the Partition Information dialog, creation of the dialog
object was creating a copy of the partition object to be displayed.  If
this was an extended partition it also included recursively constructing
the contained logical partitions too.

Instead, replace the partition object in the Dialog_Partition_Info class
with a reference to it.

NOTE:
In C++ a reference is really just a pointer under the hood.  As such,
dereferences of a pointer to an object in the context of needing a
reference to the object doesn't copy the object.  It merely initialises
the reference from the pointer.

Specifically, with this prototype:
    Dialog_Partition_Info( const Partition & partition );
and the dialog object being constructed in Win_GParted::activate_info():
    Dialog_Partition_Info dialog( *selected_partition_ptr );
the partition object is not copy constructed.  A reference (pointer) to
it is merely passed to the dialog constructor.

Bug 750168 - Reduce the amount of copying of partition objects
2015-06-10 10:43:43 -06:00
Mike Fleetwood 6ae327c8f9 Assert selected_partition_ptr is valid before use (#750168)
Further ensure that a bug doesn't get introduced with the use of
selected_partition_ptr, by asserting that it points to a current
partition object in the vector of display partitions.

After deliberately breaking the code so that selected_partition_ptr
points to some other partition object, trying to display the Information
dialog causes this crash:

======================
libparted : 2.4
======================
**
ERROR:Win_GParted.cc:989:void GParted::Win_GParted::set_valid_operations(): assertion failed: (valid_display_partition_ptr( selected_partition_ptr ))
Aborted (core dumped)

At this point in the code:

    973  void Win_GParted::set_valid_operations()
    974  {
    ...
    986          // No partition selected ...
    987          if ( ! selected_partition_ptr )
    988                  return ;
>>  989          g_assert( valid_display_partition_ptr( selected_partition_ptr ) );  // Bug: Not pointing at a valid display partition object

Bug 750168 - Reduce the amount of copying of partition objects
2015-06-10 10:43:40 -06:00
Mike Fleetwood da39e3cad3 Change selected partition into a pointer (#750168)
Now that TreeView_Details and DrawingAreaVisualDisk classes store and
pass pointers to partition objects in the Gtk signal callbacks, change
the selected partition into a pointer too.

Bug 750168 - Reduce the amount of copying of partition objects
2015-06-10 10:43:14 -06:00
Mike Fleetwood cc1448abd2 Store pointers to partition objects in DrawingAreaVisualDisk (#750168)
This stops copying of each displayed partition object into the
DrawingAreaVisualDisk class.

Bug 750168 - Reduce the amount of copying of partition objects
2015-06-10 10:43:14 -06:00
Mike Fleetwood acd5d7e580 Store pointers to partition objects in TreeView_Details (#750168)
This stops copying of each displayed partition object into the
TreeView_Details class.

It also stops copy constructing lots of partition objects when just
clicking on a partition in the disk graphic.  The disk graphic needs to
inform the main GUI and then the partition list which partition has been
selected.  The call sequence goes like:

    DrawingAreaVisualDisk::on_button_press_event(event)
      Win_GParted::on_partition_selected(partition_ptr, src_is_treeview)
        TreeView_Detail::set_selected(partition_ptr)
          TreeView_Detail::set_selected(rows, partition_ptr,
                                        inside_extended)

Relevant source and highlighted comparison line:

   140  bool TreeView_Detail::set_selected( Gtk::TreeModel::Children rows,
   141                                      const Partition * partition_ptr, bool inside_extended )
   142  {
   143          for ( unsigned int t = 0 ; t < rows .size() ; t++ )
   144          {
>> 145                  if ( static_cast<Partition>( rows[t][treeview_detail_columns.partition] ) == *partition_ptr )
   146                  {
   147                          if ( inside_extended )
   148                                  expand_all() ;
   149
   150                          set_cursor( static_cast<Gtk::TreePath>( rows[ t ] ) ) ;
   151                          return true ;
   152                  }
   153
   154                  if ( set_selected( rows[t].children(), partition_ptr, true ) )
   155                          return true ;
   156          }
   157
   158          return false ;
   159  }

Then in this function the partition selected in the disk graphic
(partition_ptr parameter) is compared in turn with each partition object
stored in the Gtk::TreeView model to find the matching one to mark it as
selected.  This mere act of accessing the partition object stored in a
row of the Gtk::TreeView model causes it to be copy constructed.  So
clicking on the 5th partition in the disk graphic will copy construct
the first 5 partition objects just to do a compare to find the matching
one.

This is because it is not possible to get a reference from a
Gtk:TreeViewProxy in gtkmm.  Merely accessing a value in a Gtk::TreeView
model takes a copy of that value.

    Subject: get a reference from a Gtk::TreeValueProxy
    http://comments.gmane.org/gmane.comp.gnome.gtkmm/2217
    http://marc.info/?t=104400417500001&r=1&w=4

Bug 750168 - Reduce the amount of copying of partition objects
2015-06-10 10:43:14 -06:00
Mike Fleetwood c430acf52a Pass by pointer in the signal_partition_selected callbacks (#750168)
Change from passing a reference to the selected partition, to passing a
pointer to the selected partition in the signal_partition_selected
callbacks between the disk graphic, partition list and core GUI modules.

This is an enabler for the following patches.

Bug 750168 - Reduce the amount of copying of partition objects
2015-06-10 10:43:14 -06:00
Mike Fleetwood 545b75d957 Move vector of partition objects to a Win_GParted class member (#750168)
Win_GParted::Refresh_Visual() used a local variable containing a copy of
the vector of partitions in the current device to be displayed.  After
visually applying pending operations it loaded copies of each partition
object into the GUI widgets to display the disk graphic and partition
list, DrawingAreaVisualDisk and TreeView_Details classes respectively.
When a partition is selected in the UI, again a partition object is
copied.  Also several of the partition dialogs, including the
information dialog, take a copy of the partition object.  All these are
copies of the same set of partition objects, those currently being
displayed in the UI.

Move the vector of displayed partitions from a local variable in
Refresh_Visual() to a Win_GParted member variable.  This will allow for
the above cases to be changed to used pointers and references to the
same set of partition objects.

The valid lifetime of pointers to elements in this partition object
vector is from one refresh to the next, when the vector is cleared and
repopulated with a new set of partition objects.  This is exactly what
is needed as the GUI widgets are reloaded on each refresh, the selected
partition is reset and none of the partition dialog objects exist.
Dialog objects being created and destroyed on each use.

On the other hand some copies of partition objects currently being
displayed, still need to be made because they have lifetimes which need
to last longer than the next call to Refresh_Visual().  Specifically the
source of the copy partition and the partition objects copied into the
in the list of pending operations.

Bug 750168 - Reduce the amount of copying of partition objects
2015-06-10 10:42:36 -06:00