2015-06-04 01:29:22 +01:00
/*************************************************************************
* Copyright ( C ) 2008 , 2011 by Volker Lanz < vl @ fidra . de > *
* *
* This program is free software ; you can redistribute it and / or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation ; either version 3 of *
* the License , or ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program . If not , see < http : //www.gnu.org/licenses/>.*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# 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"
# 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
extended partitions . ( # 232092 ) < / li >
< ! - - 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
extended partitions . ( # 232092 ) < / li >
< ! - - 3 - - >
< li > An existing NewOperation created a Partition that is now being copied . We ' re not copying
but instead creating another new Partition in its place . < / li >
< ! - - 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 --
if ( pushedDeleteOp & & & newOp - > newPartition ( ) = = & pushedDeleteOp - > deletedPartition ( ) & & ! pushedDeleteOp - > deletedPartition ( ) . roles ( ) . has ( PartitionRole : : Extended ) ) {
Log ( ) < < i18nc ( " @info/plain " , " 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 --
if ( pushedResizeOp & & & newOp - > newPartition ( ) = = & pushedResizeOp - > partition ( ) & & ! pushedResizeOp - > partition ( ) . roles ( ) . has ( PartitionRole : : Extended ) ) {
// 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.
Log ( ) < < i18nc ( " @info/plain " , " 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 --
if ( pushedCopyOp & & & newOp - > newPartition ( ) = = & pushedCopyOp - > sourcePartition ( ) ) {
Log ( ) < < i18nc ( " @info/plain " , " 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 ( ) ) {
Log ( ) < < i18nc ( " @info/plain " , " 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 ( ) ) {
Log ( ) < < i18nc ( " @info/plain " , " 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 ( ) ) {
Log ( ) < < i18nc ( " @info/plain " , " 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 ) {
2015-07-13 15:16:36 +01:00
Log ( ) < < i18nc ( " @info/plain " , " 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 {
Log ( ) < < i18nc ( " @info/plain " , " 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 ( ) ) {
Log ( ) < < i18nc ( " @info/plain " , " 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 ) {
2015-07-13 15:16:36 +01:00
Log ( ) < < i18nc ( " @info/plain " , " 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 {
Log ( ) < < i18nc ( " @info/plain " , " 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 ( ) ) {
Log ( ) < < i18nc ( " @info/plain " , " 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 ( ) ) {
Log ( ) < < i18nc ( " @info/plain " , " 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 ( ) ) ) {
Log ( ) < < i18nc ( " @info/plain " , " 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
}
/** 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
2015-07-13 15:16:36 +01:00
foreach ( Operation * currentOp , operations ( ) ) {
if ( mergeNewOperation ( currentOp , o ) )
break ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( mergeCopyOperation ( currentOp , o ) )
break ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( mergeRestoreOperation ( currentOp , o ) )
break ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( mergePartFlagsOperation ( currentOp , o ) )
break ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( mergePartLabelOperation ( currentOp , o ) )
break ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( mergeCreatePartitionTableOperation ( currentOp , o ) )
break ;
}
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
if ( o ! = nullptr ) {
2015-07-13 15:16:36 +01:00
Log ( ) < < i18nc ( " @info/plain " , " Add operation: %1 " , o - > description ( ) ) ;
operations ( ) . append ( o ) ;
o - > preview ( ) ;
o - > setStatus ( Operation : : StatusPending ) ;
}
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
// 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.
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 ;
emit operationsChanged ( ) ;
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 ( ) ;
delete o ;
}
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 ( ) ;
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
*/
Device * OperationStack : : findDeviceForPartition ( const Partition * p )
{
2015-07-13 15:16:36 +01:00
QReadLocker lockDevices ( & lock ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
foreach ( Device * d , previewDevices ( ) ) {
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
2015-07-13 15:16:36 +01:00
foreach ( const Partition * part , d - > partitionTable ( ) - > children ( ) ) {
if ( part = = p )
return d ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
foreach ( const Partition * child , part - > children ( ) )
if ( child = = p )
return d ;
}
}
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 ) ;
emit devicesChanged ( ) ;
2015-06-04 01:29:22 +01:00
}
static bool deviceLessThan ( const Device * d1 , const Device * d2 )
{
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
2015-07-13 15:16:36 +01:00
qSort ( previewDevices ( ) . begin ( ) , previewDevices ( ) . end ( ) , deviceLessThan ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
emit devicesChanged ( ) ;
2015-06-04 01:29:22 +01:00
}