2020-09-20 20:33:16 +01:00
/*
SPDX - FileCopyrightText : 2008 - 2010 Volker Lanz < vl @ fidra . de >
SPDX - FileCopyrightText : 2008 Laurent Montel < montel @ kde . org >
SPDX - FileCopyrightText : 2014 - 2020 Andrius Š tikonas < andrius @ stikonas . eu >
SPDX - FileCopyrightText : 2015 Teo Mrnjavac < teo @ kde . org >
SPDX - License - Identifier : GPL - 3.0 - or - later
*/
2015-06-04 01:29:22 +01:00
# include "core/operationstack.h"
# include "core/device.h"
# include "core/partition.h"
# include "core/partitiontable.h"
# include "ops/operation.h"
# include "ops/deleteoperation.h"
# include "ops/newoperation.h"
# include "ops/resizeoperation.h"
# include "ops/copyoperation.h"
# include "ops/restoreoperation.h"
# include "ops/createfilesystemoperation.h"
# include "ops/setpartflagsoperation.h"
# include "ops/setfilesystemlabeloperation.h"
# include "ops/createpartitiontableoperation.h"
2016-11-07 18:56:26 +00:00
# include "ops/resizevolumegroupoperation.h"
2015-06-04 01:29:22 +01:00
# include "ops/checkoperation.h"
# include "jobs/setfilesystemlabeljob.h"
# include "fs/filesystemfactory.h"
# include "util/globallog.h"
# include <KLocalizedString>
# include <QReadLocker>
# include <QWriteLocker>
/** Constructs a new OperationStack */
OperationStack : : OperationStack ( QObject * parent ) :
2015-07-13 15:16:36 +01:00
QObject ( parent ) ,
m_Operations ( ) ,
m_PreviewDevices ( ) ,
m_Lock ( QReadWriteLock : : Recursive )
2015-06-04 01:29:22 +01:00
{
}
/** Destructs an OperationStack, cleaning up Operations and Devices */
OperationStack : : ~ OperationStack ( )
{
2015-07-13 15:16:36 +01:00
clearOperations ( ) ;
clearDevices ( ) ;
2015-06-04 01:29:22 +01:00
}
/** Tries to merge an existing NewOperation with a new Operation pushed on the OperationStack
2015-07-13 15:16:36 +01:00
There are several cases what might need to be done :
< ol >
< ! - - 1 - - >
< li > An existing operation created a Partition that is now being deleted : In this case , just remove
the corresponding NewOperation from the OperationStack . < br / > This does not work for
2016-05-18 13:58:08 +01:00
extended partitions . ( # 232092 ) < / li >
2015-07-13 15:16:36 +01:00
< ! - - 2 - - >
< li > An existing Operation created a Partition that is now being moved or resized . In this case ,
remove the original NewOperation and create a new NewOperation with updated start and end
sectors . This new NewOperation is appended to the OperationStack . < br / > This does not work for
2016-05-18 13:58:08 +01:00
extended partitions . ( # 232092 ) < / li >
2015-07-13 15:16:36 +01:00
< ! - - 3 - - >
< li > An existing NewOperation created a Partition that is now being copied . We ' re not copying
2016-05-18 13:58:08 +01:00
but instead creating another new Partition in its place . < / li >
2015-07-13 15:16:36 +01:00
< ! - - 4 - - >
< li > The label for a new Partition ' s FileSystem is modified : Modify in NewOperation and forget it . < / li >
< ! - - 5 - - >
< li > File system is changed for a new Partition : Modify in NewOperation and forget it . < / li >
< ! - - 6 - - >
< li > A file system on a new Partition is about to be checked : Just delete the CheckOperation , because
file systems are checked anyway when they ' re created . This fixes # 275657. < / li >
< / ol >
@ param currentOp the Operation already on the stack to try to merge with
@ param pushedOp the newly pushed Operation
@ return true if the OperationStack has been modified in a way that requires merging to stop
2015-06-04 01:29:22 +01:00
*/
bool OperationStack : : mergeNewOperation ( Operation * & currentOp , Operation * & pushedOp )
{
2015-07-13 15:16:36 +01:00
NewOperation * newOp = dynamic_cast < NewOperation * > ( currentOp ) ;
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
if ( newOp = = nullptr )
2015-07-13 15:16:36 +01:00
return false ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
DeleteOperation * pushedDeleteOp = dynamic_cast < DeleteOperation * > ( pushedOp ) ;
ResizeOperation * pushedResizeOp = dynamic_cast < ResizeOperation * > ( pushedOp ) ;
CopyOperation * pushedCopyOp = dynamic_cast < CopyOperation * > ( pushedOp ) ;
SetFileSystemLabelOperation * pushedLabelOp = dynamic_cast < SetFileSystemLabelOperation * > ( pushedOp ) ;
CreateFileSystemOperation * pushedCreateFileSystemOp = dynamic_cast < CreateFileSystemOperation * > ( pushedOp ) ;
CheckOperation * pushedCheckOp = dynamic_cast < CheckOperation * > ( pushedOp ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
// -- 1 --
2016-05-18 13:58:08 +01:00
if ( pushedDeleteOp & & & newOp - > newPartition ( ) = = & pushedDeleteOp - > deletedPartition ( ) & & ! pushedDeleteOp - > deletedPartition ( ) . roles ( ) . has ( PartitionRole : : Extended ) ) {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Deleting a partition just created: Undoing the operation to create the partition. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
delete pushedOp ;
2015-07-22 14:48:03 +01:00
pushedOp = nullptr ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
newOp - > undo ( ) ;
delete operations ( ) . takeAt ( operations ( ) . indexOf ( newOp ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return true ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
// -- 2 --
2016-05-18 13:58:08 +01:00
if ( pushedResizeOp & & & newOp - > newPartition ( ) = = & pushedResizeOp - > partition ( ) & & ! pushedResizeOp - > partition ( ) . roles ( ) . has ( PartitionRole : : Extended ) ) {
2015-07-13 15:16:36 +01:00
// NOTE: In theory it would be possible to merge resizing an extended as long as it has no children.
// But that still doesn't save us: If we're not merging a resize on an extended that has children,
// a resizeop is added to the stack. Next, the user deletes the child. Then he resizes the
// extended again (a second resize): The ResizeOp still has the pointer to the original extended that
// will now be deleted.
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Resizing a partition just created: Updating start and end in existing operation. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
Partition * newPartition = new Partition ( newOp - > newPartition ( ) ) ;
newPartition - > setFirstSector ( pushedResizeOp - > newFirstSector ( ) ) ;
newPartition - > fileSystem ( ) . setFirstSector ( pushedResizeOp - > newFirstSector ( ) ) ;
newPartition - > setLastSector ( pushedResizeOp - > newLastSector ( ) ) ;
newPartition - > fileSystem ( ) . setLastSector ( pushedResizeOp - > newLastSector ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
NewOperation * revisedNewOp = new NewOperation ( newOp - > targetDevice ( ) , newPartition ) ;
delete pushedOp ;
pushedOp = revisedNewOp ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
newOp - > undo ( ) ;
delete operations ( ) . takeAt ( operations ( ) . indexOf ( newOp ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return true ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
// -- 3 --
2016-05-18 13:58:08 +01:00
if ( pushedCopyOp & & & newOp - > newPartition ( ) = = & pushedCopyOp - > sourcePartition ( ) ) {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Copying a new partition: Creating a new partition instead. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
Partition * newPartition = new Partition ( newOp - > newPartition ( ) ) ;
newPartition - > setFirstSector ( pushedCopyOp - > copiedPartition ( ) . firstSector ( ) ) ;
newPartition - > fileSystem ( ) . setFirstSector ( pushedCopyOp - > copiedPartition ( ) . fileSystem ( ) . firstSector ( ) ) ;
newPartition - > setLastSector ( pushedCopyOp - > copiedPartition ( ) . lastSector ( ) ) ;
newPartition - > fileSystem ( ) . setLastSector ( pushedCopyOp - > copiedPartition ( ) . fileSystem ( ) . lastSector ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
NewOperation * revisedNewOp = new NewOperation ( pushedCopyOp - > targetDevice ( ) , newPartition ) ;
delete pushedOp ;
pushedOp = revisedNewOp ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return true ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
// -- 4 --
if ( pushedLabelOp & & & newOp - > newPartition ( ) = = & pushedLabelOp - > labeledPartition ( ) ) {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Changing label for a new partition: No new operation required. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
newOp - > setLabelJob ( ) - > setLabel ( pushedLabelOp - > newLabel ( ) ) ;
newOp - > newPartition ( ) . fileSystem ( ) . setLabel ( pushedLabelOp - > newLabel ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
delete pushedOp ;
2015-07-22 14:48:03 +01:00
pushedOp = nullptr ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return true ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
// -- 5 --
if ( pushedCreateFileSystemOp & & & newOp - > newPartition ( ) = = & pushedCreateFileSystemOp - > partition ( ) ) {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Changing file system for a new partition: No new operation required. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
FileSystem * oldFs = & newOp - > newPartition ( ) . fileSystem ( ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
newOp - > newPartition ( ) . setFileSystem ( FileSystemFactory : : cloneWithNewType ( pushedCreateFileSystemOp - > newFileSystem ( ) - > type ( ) , * oldFs ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
delete oldFs ;
2015-07-22 14:48:03 +01:00
oldFs = nullptr ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
delete pushedOp ;
2015-07-22 14:48:03 +01:00
pushedOp = nullptr ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return true ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
// -- 6 --
if ( pushedCheckOp & & & newOp - > newPartition ( ) = = & pushedCheckOp - > checkedPartition ( ) ) {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Checking file systems is automatically done when creating them: No new operation required. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
delete pushedOp ;
2015-07-22 14:48:03 +01:00
pushedOp = nullptr ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return true ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return false ;
2015-06-04 01:29:22 +01:00
}
2015-07-13 15:16:36 +01:00
/** Tries to merge an existing CopyOperation with a new Operation pushed on the OperationStack.
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
These are the cases to consider :
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
< ol >
< ! - - 1 - - >
< li > An existing CopyOperation created a Partition that is now being deleted . Remove the
CopyOperation , and , if the CopyOperation was an overwrite , carry on with the delete . Else
also remove the DeleteOperation . < / li >
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
< ! - - 2 - - >
< li > An existing CopyOperation created a Partition that is now being copied . We ' re not copying
the target of this existing CopyOperation , but its source instead . If this merge is not done ,
copied partitions will have misleading labels ( " copy of sdXY " instead of " copy of copy of
sdXY " for a second-generation copy) but the Operation itself will still work.</li>
< / ol >
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
@ param currentOp the Operation already on the stack to try to merge with
@ param pushedOp the newly pushed Operation
@ return true if the OperationStack has been modified in a way that requires merging to stop
2015-06-04 01:29:22 +01:00
*/
bool OperationStack : : mergeCopyOperation ( Operation * & currentOp , Operation * & pushedOp )
{
2015-07-13 15:16:36 +01:00
CopyOperation * copyOp = dynamic_cast < CopyOperation * > ( currentOp ) ;
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
if ( copyOp = = nullptr )
2015-07-13 15:16:36 +01:00
return false ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
DeleteOperation * pushedDeleteOp = dynamic_cast < DeleteOperation * > ( pushedOp ) ;
CopyOperation * pushedCopyOp = dynamic_cast < CopyOperation * > ( pushedOp ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
// -- 1 --
if ( pushedDeleteOp & & & copyOp - > copiedPartition ( ) = = & pushedDeleteOp - > deletedPartition ( ) ) {
// If the copy operation didn't overwrite, but create a new partition, just remove the
// copy operation, forget the delete and be done.
2015-07-22 14:48:03 +01:00
if ( copyOp - > overwrittenPartition ( ) = = nullptr ) {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Deleting a partition just copied: Removing the copy. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
delete pushedOp ;
2015-07-22 14:48:03 +01:00
pushedOp = nullptr ;
2015-07-13 15:16:36 +01:00
} else {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Deleting a partition just copied over an existing partition: Removing the copy and deleting the existing partition. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
pushedDeleteOp - > setDeletedPartition ( copyOp - > overwrittenPartition ( ) ) ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
copyOp - > undo ( ) ;
delete operations ( ) . takeAt ( operations ( ) . indexOf ( copyOp ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return true ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
// -- 2 --
if ( pushedCopyOp & & & copyOp - > copiedPartition ( ) = = & pushedCopyOp - > sourcePartition ( ) ) {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Copying a partition that is itself a copy: Copying the original source partition instead. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
pushedCopyOp - > setSourcePartition ( & copyOp - > sourcePartition ( ) ) ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return false ;
2015-06-04 01:29:22 +01:00
}
/** Tries to merge an existing RestoreOperation with a new Operation pushed on the OperationStack.
2015-07-13 15:16:36 +01:00
If an existing RestoreOperation created a Partition that is now being deleted , remove the
RestoreOperation , and , if the RestoreOperation was an overwrite , carry on with the delete . Else
also remove the DeleteOperation .
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
@ param currentOp the Operation already on the stack to try to merge with
@ param pushedOp the newly pushed Operation
@ return true if the OperationStack has been modified in a way that requires merging to stop
2015-06-04 01:29:22 +01:00
*/
bool OperationStack : : mergeRestoreOperation ( Operation * & currentOp , Operation * & pushedOp )
{
2015-07-13 15:16:36 +01:00
RestoreOperation * restoreOp = dynamic_cast < RestoreOperation * > ( currentOp ) ;
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
if ( restoreOp = = nullptr )
2015-07-13 15:16:36 +01:00
return false ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
DeleteOperation * pushedDeleteOp = dynamic_cast < DeleteOperation * > ( pushedOp ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( pushedDeleteOp & & & restoreOp - > restorePartition ( ) = = & pushedDeleteOp - > deletedPartition ( ) ) {
2015-07-22 14:48:03 +01:00
if ( restoreOp - > overwrittenPartition ( ) = = nullptr ) {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Deleting a partition just restored: Removing the restore operation. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
delete pushedOp ;
2015-07-22 14:48:03 +01:00
pushedOp = nullptr ;
2015-07-13 15:16:36 +01:00
} else {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Deleting a partition just restored to an existing partition: Removing the restore operation and deleting the existing partition. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
pushedDeleteOp - > setDeletedPartition ( restoreOp - > overwrittenPartition ( ) ) ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
restoreOp - > undo ( ) ;
delete operations ( ) . takeAt ( operations ( ) . indexOf ( restoreOp ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return true ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return false ;
2015-06-04 01:29:22 +01:00
}
/** Tries to merge an existing SetPartFlagsOperation with a new Operation pushed on the OperationStack.
2015-07-13 15:16:36 +01:00
If the Partition flags for an existing Partition are modified look if there is an existing
Operation for the same Partition and modify that one .
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
@ param currentOp the Operation already on the stack to try to merge with
@ param pushedOp the newly pushed Operation
@ return true if the OperationStack has been modified in a way that requires merging to stop
2015-06-04 01:29:22 +01:00
*/
bool OperationStack : : mergePartFlagsOperation ( Operation * & currentOp , Operation * & pushedOp )
{
2015-07-13 15:16:36 +01:00
SetPartFlagsOperation * partFlagsOp = dynamic_cast < SetPartFlagsOperation * > ( currentOp ) ;
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
if ( partFlagsOp = = nullptr )
2015-07-13 15:16:36 +01:00
return false ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
SetPartFlagsOperation * pushedFlagsOp = dynamic_cast < SetPartFlagsOperation * > ( pushedOp ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( pushedFlagsOp & & & partFlagsOp - > flagPartition ( ) = = & pushedFlagsOp - > flagPartition ( ) ) {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Changing flags again for the same partition: Removing old operation. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
pushedFlagsOp - > setOldFlags ( partFlagsOp - > oldFlags ( ) ) ;
partFlagsOp - > undo ( ) ;
delete operations ( ) . takeAt ( operations ( ) . indexOf ( partFlagsOp ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return true ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return false ;
2015-06-04 01:29:22 +01:00
}
/** Tries to merge an existing SetFileSystemLabelOperation with a new Operation pushed on the OperationStack.
2015-07-13 15:16:36 +01:00
If a FileSystem label for an existing Partition is modified look if there is an existing
SetFileSystemLabelOperation for the same Partition .
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
@ param currentOp the Operation already on the stack to try to merge with
@ param pushedOp the newly pushed Operation
@ return true if the OperationStack has been modified in a way that requires merging to stop
2015-06-04 01:29:22 +01:00
*/
bool OperationStack : : mergePartLabelOperation ( Operation * & currentOp , Operation * & pushedOp )
{
2015-07-13 15:16:36 +01:00
SetFileSystemLabelOperation * partLabelOp = dynamic_cast < SetFileSystemLabelOperation * > ( currentOp ) ;
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
if ( partLabelOp = = nullptr )
2015-07-13 15:16:36 +01:00
return false ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
SetFileSystemLabelOperation * pushedLabelOp = dynamic_cast < SetFileSystemLabelOperation * > ( pushedOp ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( pushedLabelOp & & & partLabelOp - > labeledPartition ( ) = = & pushedLabelOp - > labeledPartition ( ) ) {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Changing label again for the same partition: Removing old operation. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
pushedLabelOp - > setOldLabel ( partLabelOp - > oldLabel ( ) ) ;
partLabelOp - > undo ( ) ;
delete operations ( ) . takeAt ( operations ( ) . indexOf ( partLabelOp ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return true ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return false ;
2015-06-04 01:29:22 +01:00
}
/** Tries to merge an existing CreatePartitionTableOperation with a new Operation pushed on the OperationStack.
2015-07-13 15:16:36 +01:00
If a new partition table is to be created on a device and a previous operation targets that
device , remove this previous operation .
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
@ param currentOp the Operation already on the stack to try to merge with
@ param pushedOp the newly pushed Operation
@ return true if the OperationStack has been modified in a way that requires merging to stop
2015-06-04 01:29:22 +01:00
*/
bool OperationStack : : mergeCreatePartitionTableOperation ( Operation * & currentOp , Operation * & pushedOp )
{
2015-07-13 15:16:36 +01:00
CreatePartitionTableOperation * pushedCreatePartitionTableOp = dynamic_cast < CreatePartitionTableOperation * > ( pushedOp ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( pushedCreatePartitionTableOp & & currentOp - > targets ( pushedCreatePartitionTableOp - > targetDevice ( ) ) ) {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Creating new partition table, discarding previous operation on device. " ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
CreatePartitionTableOperation * createPartitionTableOp = dynamic_cast < CreatePartitionTableOperation * > ( currentOp ) ;
2015-07-22 14:48:03 +01:00
if ( createPartitionTableOp ! = nullptr )
2015-07-13 15:16:36 +01:00
pushedCreatePartitionTableOp - > setOldPartitionTable ( createPartitionTableOp - > oldPartitionTable ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
currentOp - > undo ( ) ;
delete operations ( ) . takeAt ( operations ( ) . indexOf ( currentOp ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return true ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return false ;
2015-06-04 01:29:22 +01:00
}
2016-11-07 18:56:26 +00:00
bool OperationStack : : mergeResizeVolumeGroupResizeOperation ( Operation * & pushedOp )
{
ResizeVolumeGroupOperation * pushedResizeVolumeGroupOp = dynamic_cast < ResizeVolumeGroupOperation * > ( pushedOp ) ;
if ( pushedResizeVolumeGroupOp & & pushedResizeVolumeGroupOp - > jobs ( ) . count ( ) = = 0 ) {
Log ( ) < < xi18nc ( " @info:status " , " Resizing Volume Group, nothing to do. " ) ;
return true ;
}
return false ;
}
2015-06-04 01:29:22 +01:00
/** Pushes a new Operation on the OperationStack.
2015-07-13 15:16:36 +01:00
This method will call all methods that try to merge the new Operation with the
existing ones . It is not uncommon that any of these will delete the pushed
Operation . Callers < b > must not rely < / b > on the pushed Operation to exist after
calling OperationStack : : push ( ) .
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
@ param o Pointer to the Operation . Must not be nullptr .
2015-06-04 01:29:22 +01:00
*/
void OperationStack : : push ( Operation * o )
{
2015-07-13 15:16:36 +01:00
Q_ASSERT ( o ) ;
2015-06-04 01:29:22 +01:00
2016-11-07 18:56:26 +00:00
if ( mergeResizeVolumeGroupResizeOperation ( o ) )
return ;
2016-07-08 00:57:16 +01:00
for ( auto currentOp = operations ( ) . rbegin ( ) ; currentOp ! = operations ( ) . rend ( ) ; + + currentOp ) {
2016-05-19 16:40:20 +01:00
if ( mergeNewOperation ( * currentOp , o ) )
2015-07-13 15:16:36 +01:00
break ;
2015-06-04 01:29:22 +01:00
2016-05-19 16:40:20 +01:00
if ( mergeCopyOperation ( * currentOp , o ) )
2015-07-13 15:16:36 +01:00
break ;
2015-06-04 01:29:22 +01:00
2016-05-19 16:40:20 +01:00
if ( mergeRestoreOperation ( * currentOp , o ) )
2015-07-13 15:16:36 +01:00
break ;
2015-06-04 01:29:22 +01:00
2016-05-19 16:40:20 +01:00
if ( mergePartFlagsOperation ( * currentOp , o ) )
2015-07-13 15:16:36 +01:00
break ;
2015-06-04 01:29:22 +01:00
2016-05-19 16:40:20 +01:00
if ( mergePartLabelOperation ( * currentOp , o ) )
2015-07-13 15:16:36 +01:00
break ;
2015-06-04 01:29:22 +01:00
2016-05-19 16:40:20 +01:00
if ( mergeCreatePartitionTableOperation ( * currentOp , o ) )
2015-07-13 15:16:36 +01:00
break ;
}
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
if ( o ! = nullptr ) {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:status " , " Add operation: %1 " , o - > description ( ) ) ;
2015-07-13 15:16:36 +01:00
operations ( ) . append ( o ) ;
o - > preview ( ) ;
o - > setStatus ( Operation : : StatusPending ) ;
}
2015-06-04 01:29:22 +01:00
2020-09-15 02:36:46 +01:00
// Q_EMIT operationsChanged even if o is nullptr because it has been merged: merging might
2015-07-13 15:16:36 +01:00
// have led to an existing operation changing.
2020-09-15 02:36:46 +01:00
Q_EMIT operationsChanged ( ) ;
2015-06-04 01:29:22 +01:00
}
/** Removes the topmost Operation from the OperationStack, calls Operation::undo() on it and deletes it. */
void OperationStack : : pop ( )
{
2015-07-13 15:16:36 +01:00
Operation * o = operations ( ) . takeLast ( ) ;
o - > undo ( ) ;
delete o ;
2020-09-15 02:36:46 +01:00
Q_EMIT operationsChanged ( ) ;
2015-06-04 01:29:22 +01:00
}
2016-05-18 14:56:13 +01:00
/** Check whether previous operations involve given partition.
@ param p Pointer to the Partition . Must not be nullptr .
*/
bool OperationStack : : contains ( const Partition * p ) const
{
Q_ASSERT ( p ) ;
2016-08-11 14:26:54 +01:00
for ( const auto & o : operations ( ) ) {
2016-05-18 14:56:13 +01:00
if ( o - > targets ( * p ) )
return true ;
2016-05-19 01:53:30 +01:00
2016-05-18 15:45:00 +01:00
CopyOperation * copyOp = dynamic_cast < CopyOperation * > ( o ) ;
2016-05-19 01:53:30 +01:00
if ( copyOp ) {
const Partition * source = & copyOp - > sourcePartition ( ) ;
if ( source = = p )
return true ;
}
2016-05-18 14:56:13 +01:00
}
return false ;
}
2015-06-04 01:29:22 +01:00
/** Removes all Operations from the OperationStack, calling Operation::undo() on them and deleting them. */
void OperationStack : : clearOperations ( )
{
2015-07-13 15:16:36 +01:00
while ( ! operations ( ) . isEmpty ( ) ) {
Operation * o = operations ( ) . takeLast ( ) ;
if ( o - > status ( ) = = Operation : : StatusPending )
o - > undo ( ) ;
2016-05-11 22:17:38 +01:00
delete o ;
2015-07-13 15:16:36 +01:00
}
2020-09-15 02:36:46 +01:00
Q_EMIT operationsChanged ( ) ;
2015-06-04 01:29:22 +01:00
}
/** Clears the list of Devices. */
void OperationStack : : clearDevices ( )
{
2015-07-13 15:16:36 +01:00
QWriteLocker lockDevices ( & lock ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
qDeleteAll ( previewDevices ( ) ) ;
previewDevices ( ) . clear ( ) ;
2020-09-15 02:36:46 +01:00
Q_EMIT devicesChanged ( ) ;
2015-06-04 01:29:22 +01:00
}
/** Finds a Device a Partition is on.
2015-07-13 15:16:36 +01:00
@ param p pointer to the Partition to find a Device for
2015-07-22 14:48:03 +01:00
@ return the Device or nullptr if none could be found
2015-06-04 01:29:22 +01:00
*/
2016-08-08 22:33:17 +01:00
Device * OperationStack : : findDeviceForPartition ( const Partition * p )
2015-06-04 01:29:22 +01:00
{
2015-07-13 15:16:36 +01:00
QReadLocker lockDevices ( & lock ( ) ) ;
2015-06-04 01:29:22 +01:00
2016-08-11 14:26:54 +01:00
const auto devices = previewDevices ( ) ;
for ( Device * d : devices ) {
2015-07-22 14:48:03 +01:00
if ( d - > partitionTable ( ) = = nullptr )
2015-07-13 15:16:36 +01:00
continue ;
2015-06-04 01:29:22 +01:00
2016-08-11 14:26:54 +01:00
const auto partitions = d - > partitionTable ( ) - > children ( ) ;
for ( const auto * part : partitions ) {
2015-07-13 15:16:36 +01:00
if ( part = = p )
return d ;
2015-06-04 01:29:22 +01:00
2016-08-11 14:26:54 +01:00
for ( const auto & child : part - > children ( ) )
2016-08-08 18:37:21 +01:00
if ( child = = p )
return d ;
2015-07-13 15:16:36 +01:00
}
}
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
return nullptr ;
2015-06-04 01:29:22 +01:00
}
/** Adds a Device to the OperationStack
2015-07-22 14:48:03 +01:00
@ param d pointer to the Device to add . Must not be nullptr .
2015-06-04 01:29:22 +01:00
*/
void OperationStack : : addDevice ( Device * d )
{
2015-07-13 15:16:36 +01:00
Q_ASSERT ( d ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
QWriteLocker lockDevices ( & lock ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
previewDevices ( ) . append ( d ) ;
2020-09-15 02:36:46 +01:00
Q_EMIT devicesChanged ( ) ;
2015-06-04 01:29:22 +01:00
}
static bool deviceLessThan ( const Device * d1 , const Device * d2 )
{
2017-10-06 03:17:51 +01:00
// Display alphabetically sorted disk devices above LVM VGs
2018-04-09 02:57:45 +01:00
if ( d1 - > type ( ) = = Device : : Type : : LVM_Device & & d2 - > type ( ) = = Device : : Type : : Disk_Device )
2017-10-06 03:17:51 +01:00
return false ;
2015-07-13 15:16:36 +01:00
return d1 - > deviceNode ( ) < = d2 - > deviceNode ( ) ;
2015-06-04 01:29:22 +01:00
}
void OperationStack : : sortDevices ( )
{
2015-07-13 15:16:36 +01:00
QWriteLocker lockDevices ( & lock ( ) ) ;
2015-06-04 01:29:22 +01:00
2017-05-03 19:24:20 +01:00
std : : sort ( previewDevices ( ) . begin ( ) , previewDevices ( ) . end ( ) , deviceLessThan ) ;
2015-06-04 01:29:22 +01:00
2020-09-15 02:36:46 +01:00
Q_EMIT devicesChanged ( ) ;
2015-06-04 01:29:22 +01:00
}