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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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.
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
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;
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.
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
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
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
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
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
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
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
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
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
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
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.
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
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
Capture and parse the progress reports of ntfsresize and resize2fs and
update the dialog progress bar.
Bug 467925 - gparted: add progress bar during operation
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