Parse file system mount options string from file and mount command
output, extracting the setting for the read-only flag and storing in the
mount maps. Read-only flag for swap space gets the struct MountEntry
constructor default of false.
Closes#10 - Gparted fails to resize btrfs partition that is mounted
read-only
Just updates the 2 maps in the Mount_Info module so that they also have
a read-only flag for each mount. Ensure that when a struct MountEntry
is created the readonly bool POD (Plain Old Data) type is initialised by
the constructor. Nothing yet sets or uses the flag.
Closes#10 - Gparted fails to resize btrfs partition that is mounted
read-only
The function was using std::map::count() [1] to test if the file system
entry existed in the map before looking up the value using
std::map::operator[] to avoid having operator[] inserting elements which
don't exist [2].
Rewrite using std::map::find() [3] so that map is only searched once,
and so that it is more obvious what is happening without having to know
the subtleties of std::map::count() and ::operator[].
[1] std::map::count()
http://www.cplusplus.com/reference/map/map/count/
"Searches the container for elements with a key equivalent to k and
returns the number of matches.
Because all elements in a map container are unique, the function can
only return 1 (if the element is found) or zero (otherwise).
"
[2] std::map::operator[]
http://www.cplusplus.com/reference/map/map/operator[]/
"If k does not match the key of any element in the container, the
function inserts a new element with that key and returns a reference
to its mapped value. Notice that this always increases the
container size by one, even if no mapped value is assigned to the
element (the element is constructed using its default constructor).
"
[3] std::map::find
http://www.cplusplus.com/reference/map/map/find/
"Searches the container for an element with a key equivalent to k
and returns an iterator to it if found, otherwise it returns an
iterator to map::end.
"
There is no prospect of there being ufs-tools on Linux. The was a
project which did release ufs-tools version 0.1 in 2004, but has been
inactive since then.
http://ufs-linux.sourceforge.net/
Copying and moving is now implemented for file systems in the basic
supported category. Also mounting and unmounting of unsupported file
system and reporting their usage while mounted has been added. This is
all the support that GParted has ever implemented for UFS. Therefore
re-assign UFS as a basic supported file system as it looses no
functionality.
Closes!13 - Support copying and moving of unsupported partition content
Want a single term under which the supported actions for all basic
supported file systems are displayed in the File System Support dialog.
"Unknown" isn't the correct adjective because the group includes
unknown, but also includes: BitLocker, GRUB2 core image, ISO9660, Linux
SWRaid, Linux Suspend, REFS and ZFS. Add "other" file system type just
for displaying in the dialog.
Closes!13 - Support copying and moving of unsupported partition content
Introduce a third category of basic file system support to go along with
the existing full and none. Use the file system's entry in
FILESYSTEM_MAP to determine the level of support. See comment in
GParted_Core::init_filesystems() for details.
Add and remove FILESYSTEM_MAP NULL pointer entries as required, so that
only the file system types intended to have basic support have such
entries.
Closes!13 - Support copying and moving of unsupported partition content
PATCHSET OVERVIEW:
Forum user wanted to be able to move a partition with unknown content:
Topic: Can't move/rezise partition on android device (unknown format)
http://gparted-forum.surf4.info/viewtopic.php?id=17742
While GParted isn't going to be able to run any sort of file system
check on the unknown content there isn't any reason why such a partition
can't be copied or moved so long as the partition stays the same size.
GParted can just use it's existing internal block copy routine it uses
for copying and moving most partition content. This is no different to
a few of the already supported file system types which don't have a
check-repair tool: exfat, f2fs, nilfs2, udf, ufs.
This patchset introduces a third category called basic file system
support to go along with the existing full and unsupported categories.
Basic supported file systems will just use GParted's inbuilt
capabilities to perform actions so they won't need a derived FileSystem
implementation class. Unknown file systems along with all other
recognised, but otherwise unsupported, file systems will be assigned to
this new basic supported category.
THIS PATCH:
FS_UNKNOWN is used when GParted is unable to identify the contents of a
partition. FS_UNKNOWN is also used to generate a file system support
set with no supported actions, in the FileSystem::FS::FS() constructor
and in GParted_Core::get_fs().
As support for operations on partitions with unknown content is being
added, the second usage will be confusing or even wrong.
FS( FS_UNKNOWN ) constructs the no supported actions set, yet GParted
will support some actions for the FS_UNKNOWN file system type.
Therefore add FS_UNSUPPORTED for the second usage.
Closes!13 - Support copying and moving of unsupported partition content
Util-linux package, at least as far back as version 2.23.2 as found on
CentOS 7, provides the mkfs.minix and fsck.minix commands. Also blkid
from the same package, recognises minix file systems.
Create version 3 file systems because MINIX 3 [1] is the only supported
version and that reportedly uses version 3 of the file system [2].
[1] MINIX 3 / History
https://en.wikipedia.org/wiki/MINIX_3#History
[2] Regarding MINIX 3 file system
https://groups.google.com/forum/#!topic/minix3/3-TeHR_23X8
"MINIX 3 uses Minix File System (MFS). More precisely MFS V3."
Closes!12 - Add minix file system support
Usage of members label_device_info1 and label_device_info2 was removed
in this commit from 2004.
8ae5ebb2e6
several (mostly) i18n related fixes/cleanups
The CUSTOM_TEXT enumeration is exclusively used as the type of one of
the parameters to the functions get_generic_text() and get_custom_text()
in the FileSystem class and derived classes. The definition of the
enumeration therefore belongs in FileSystem.h. Move it.
After a failed LUKS unlock attempt the password entry dialog shows the
error "Failed to open LUKS encryption". Improve the user experience by
clearing that error message at the start of the next attempt to avoid
contradictory information with the main windows status of "Opening
encryption on $PARTITION" whilst performing the next unlock attempt.
Bug 795617 - Implement opening and closing of LUKS mappings
The Change_UUID_Warning vectors were fat16 and ntfs class member
variables, but are only ever accessed in the get_custom_text() method.
Make them local variables in get_custom_text() instead. Static so that
references to them can be returned.
Same case as for FileSystem Label dialog before; the Partition Name
dialog only has a single line of just 2 widgets. Therefore switch to a
simpler horizontal box widget to lay them out.
The FileSystem Label dialog only has a single line of just 2 widgets; a
text label and entry box widget. There is no need to use a multi-line
capable table to hold this. Switch to a simpler horizontal box widget.
Note that this change is not related to porting to Gtk 3 and stopping
using deprecated APIs because both HBox [1] and Table [2] are deprecated
in Gtk 3.2 and Gtk 3.4 and replaced by Box with horizontal orientation
and Grid respectively.
[1] NEWS file from gtkmm 3.2, actually first released in gtkmm 3.1.6
(unstable):
https://git.gnome.org/browse/gtkmm/tree/NEWS?h=3.2.0#n91
"Gtk:
* All H* or V* specialized classes have been deprecated, to
match the deprecations in the GTK+ C API. You should now
set the orientation instead.
This includes HBox, VBox, HButtonBox, VButtonBox, HPaned,
VPaned, HScale, VScale, HSeparator, VSeparator, HScrollbar
and VScrollbar."
[2] NEWS file from gtkmm 3.4, actually first released in gtkmm 3.3.2
(unstable):
https://git.gnome.org/browse/gtkmm/tree/NEWS?h=3.4.0#n162
"* Deprecate Gtk::Table in favour of Gtk::Grid."
Replace return by value of const strings from
FileSystem::get_custom_text() and get_generic_text() because that
implies duplication of those strings. Return a reference to constant
strings instead.
Replace the insert() method (which reports an error when inserting a
password with a key which already exists) with the store() method which
replaces or inserts the password depending on whether the key already
exists or not respectively. There is also an optimisation that nothing
is changed if the password to be replaced is the same as the one already
stored. The code in Win_GParted::open_encrypted_partition() is
simplified now it doesn't have to implement this pattern of behaviour
itself.
Bug 795617 - Implement opening and closing of LUKS mappings
Reports generic GParted error "Failed to open LUKS encryption" on any
failure unlocking the partition. Choosing not to display cryptsetup
reported errors because those messages and their translations are not
under GParted control.
Bug 795617 - Implement opening and closing of LUKS mappings
The underlying C coded Gtk Entry widget is careful to zero memory after
use, allowing the widget to be safely used for password entry [1].
However the C++ method Gtk::Entry::get_text() just takes the underlying
C string from the Gtk Entry widget and copies it when constructing a
Glib::ustring for the return value [2].
So directly use the Gtk/C API to get the C string instead.
[1] https://git.gnome.org/browse/gtk+/tree/gtk/gtkentrybuffer.c?h=3.22.28#n92
See function trash_area() which zeros memory and its use in
gtk_entry_buffer_normal_insert_text(),
gtk_entry_buffer_normal_delete_text() and
gtk_entry_buffer_finalize().
[2] https://git.gnome.org/browse/gtkmm/tree/gtk/src/entry.hg?h=3.22.2#n104
_WRAP_METHOD(Glib::ustring get_text() const, gtk_entry_get_text)
https://git.gnome.org/browse/glibmm/tree/docs/internal/using_gmmproc.txt?h=2.46.1#n53
_WRAP_METHOD(Glib::ustring METHOD const, FUNC) is processed to:
Glib::ustring METHOD() const
{
return Glib::convert_const_gchar_ptr_to_ustring(
FUNC(const_cast<GtkEntry*>(gobj())));
}
https://git.gnome.org/browse/glibmm/tree/glib/glibmm/utility.h?h=2.46.1#n82
Glib::ustring convert_const_gchar_ptr_to_ustring(const char* str)
{
return (str) ? Glib::ustring(str) : Glib::ustring();
}
So Gtk::Entry::get_text() calls Glib::ustring() constructor which
copies the C string to create the Glib::ustring object returned.
Bug 795617 - Implement opening and closing of LUKS mappings
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
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
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
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
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
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
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
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
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
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.
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.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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