2015-06-04 01:29:22 +01:00
/*************************************************************************
* Copyright ( C ) 2008 by Volker Lanz < vl @ fidra . de > *
2016-03-02 19:00:31 +00:00
* Copyright ( C ) 2016 by Andrius Š tikonas < andrius @ stikonas . eu > *
2015-06-04 01:29:22 +01:00
* *
* 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 "ops/restoreoperation.h"
# include "core/partition.h"
# include "core/device.h"
# include "core/partitiontable.h"
# include "core/partitionnode.h"
# include "jobs/createpartitionjob.h"
# include "jobs/deletepartitionjob.h"
# include "jobs/checkfilesystemjob.h"
# include "jobs/restorefilesystemjob.h"
# include "jobs/resizefilesystemjob.h"
# include "fs/filesystem.h"
# include "fs/filesystemfactory.h"
2016-05-11 23:00:37 +01:00
# include "fs/luks.h"
2015-06-04 01:29:22 +01:00
# include "util/capacity.h"
# include "util/report.h"
# include <QDebug>
# include <QString>
# include <QFileInfo>
# include <KLocalizedString>
/** Creates a new RestoreOperation.
2015-07-13 15:16:36 +01:00
@ param d the Device to restore the Partition to
2015-07-22 14:48:03 +01:00
@ param p pointer to the Partition that will be restored . May not be nullptr .
2015-07-13 15:16:36 +01:00
@ param filename name of the image file to restore from
2015-06-04 01:29:22 +01:00
*/
RestoreOperation : : RestoreOperation ( Device & d , Partition * p , const QString & filename ) :
2015-07-13 15:16:36 +01:00
Operation ( ) ,
m_TargetDevice ( d ) ,
m_RestorePartition ( p ) ,
m_FileName ( filename ) ,
2015-07-22 14:48:03 +01:00
m_OverwrittenPartition ( nullptr ) ,
2015-07-13 15:16:36 +01:00
m_MustDeleteOverwritten ( false ) ,
m_ImageLength ( QFileInfo ( filename ) . size ( ) / 512 ) , // 512 being the "sector size" of an image file.
2015-07-22 14:48:03 +01:00
m_CreatePartitionJob ( nullptr ) ,
m_RestoreJob ( nullptr ) ,
m_CheckTargetJob ( nullptr ) ,
m_MaximizeJob ( nullptr )
2015-06-04 01:29:22 +01:00
{
2015-07-13 15:16:36 +01:00
restorePartition ( ) . setState ( Partition : : StateRestore ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
Q_ASSERT ( targetDevice ( ) . partitionTable ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
Partition * dest = targetDevice ( ) . partitionTable ( ) - > findPartitionBySector ( restorePartition ( ) . firstSector ( ) , PartitionRole ( PartitionRole : : Primary | PartitionRole : : Logical | PartitionRole : : Unallocated ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-22 14:48:03 +01:00
if ( dest = = nullptr )
2015-07-13 15:16:36 +01:00
qWarning ( ) < < " destination partition not found at sector " < < restorePartition ( ) . firstSector ( ) ;
2015-06-04 01:29:22 +01:00
2015-07-23 16:55:17 +01:00
Q_ASSERT ( dest ) ;
2015-07-13 15:16:36 +01:00
if ( dest & & ! dest - > roles ( ) . has ( PartitionRole : : Unallocated ) ) {
restorePartition ( ) . setLastSector ( dest - > lastSector ( ) ) ;
setOverwrittenPartition ( dest ) ;
removePreviewPartition ( targetDevice ( ) , * dest ) ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( ! overwrittenPartition ( ) )
addJob ( m_CreatePartitionJob = new CreatePartitionJob ( targetDevice ( ) , restorePartition ( ) ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
addJob ( m_RestoreJob = new RestoreFileSystemJob ( targetDevice ( ) , restorePartition ( ) , fileName ( ) ) ) ;
addJob ( m_CheckTargetJob = new CheckFileSystemJob ( restorePartition ( ) ) ) ;
addJob ( m_MaximizeJob = new ResizeFileSystemJob ( targetDevice ( ) , restorePartition ( ) ) ) ;
2015-06-04 01:29:22 +01:00
}
RestoreOperation : : ~ RestoreOperation ( )
{
2015-07-13 15:16:36 +01:00
if ( status ( ) = = StatusPending )
delete m_RestorePartition ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( status ( ) = = StatusFinishedSuccess | | status ( ) = = StatusFinishedWarning | | status ( ) = = StatusError )
cleanupOverwrittenPartition ( ) ;
2015-06-04 01:29:22 +01:00
}
bool RestoreOperation : : targets ( const Device & d ) const
{
2015-07-13 15:16:36 +01:00
return d = = targetDevice ( ) ;
2015-06-04 01:29:22 +01:00
}
bool RestoreOperation : : targets ( const Partition & p ) const
{
2015-07-13 15:16:36 +01:00
return p = = restorePartition ( ) ;
2015-06-04 01:29:22 +01:00
}
void RestoreOperation : : preview ( )
{
2015-07-13 15:16:36 +01:00
insertPreviewPartition ( targetDevice ( ) , restorePartition ( ) ) ;
2015-06-04 01:29:22 +01:00
}
void RestoreOperation : : undo ( )
{
2015-07-13 15:16:36 +01:00
removePreviewPartition ( targetDevice ( ) , restorePartition ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( overwrittenPartition ( ) )
insertPreviewPartition ( targetDevice ( ) , * overwrittenPartition ( ) ) ;
2015-06-04 01:29:22 +01:00
}
bool RestoreOperation : : execute ( Report & parent )
{
2015-07-13 15:16:36 +01:00
bool rval = false ;
bool warning = false ;
Report * report = parent . newChild ( description ( ) ) ;
if ( overwrittenPartition ( ) )
restorePartition ( ) . setPartitionPath ( overwrittenPartition ( ) - > devicePath ( ) ) ;
if ( overwrittenPartition ( ) | | ( rval = createPartitionJob ( ) - > run ( * report ) ) ) {
restorePartition ( ) . setState ( Partition : : StateNone ) ;
if ( ( rval = restoreJob ( ) - > run ( * report ) ) ) {
if ( ( rval = checkTargetJob ( ) - > run ( * report ) ) ) {
// If the partition was written over an existing one, the partition itself may now
// be larger than the filesystem, so maximize the filesystem to the partition's size
// or the image length, whichever is larger. If this fails, don't return an error, just
// warn the user.
if ( ( warning = ! maximizeJob ( ) - > run ( * report ) ) )
2016-07-17 23:41:00 +01:00
report - > line ( ) < < xi18nc ( " @info:status " , " <warning>Maximizing file system on target partition <filename>%1</filename> to the size of the partition failed.</warning> " , restorePartition ( ) . deviceNode ( ) ) ;
2015-07-13 15:16:36 +01:00
} else
2016-07-17 23:41:00 +01:00
report - > line ( ) < < xi18nc ( " @info:status " , " Checking target file system on partition <filename>%1</filename> after the restore failed. " , restorePartition ( ) . deviceNode ( ) ) ;
2015-07-13 15:16:36 +01:00
} else {
if ( ! overwrittenPartition ( ) )
DeletePartitionJob ( targetDevice ( ) , restorePartition ( ) ) . run ( * report ) ;
2016-07-17 23:41:00 +01:00
report - > line ( ) < < xi18nc ( " @info:status " , " Restoring file system failed. " ) ;
2015-07-13 15:16:36 +01:00
}
} else
2016-07-17 23:41:00 +01:00
report - > line ( ) < < xi18nc ( " @info:status " , " Creating the destination partition to restore to failed. " ) ;
2015-07-13 15:16:36 +01:00
if ( rval )
setStatus ( warning ? StatusFinishedWarning : StatusFinishedSuccess ) ;
else
setStatus ( StatusError ) ;
2016-07-17 23:41:00 +01:00
report - > setStatus ( xi18nc ( " @info:status (success, error, warning...) of operation " , " %1: %2 " , description ( ) , statusText ( ) ) ) ;
2015-07-13 15:16:36 +01:00
return rval ;
2015-06-04 01:29:22 +01:00
}
QString RestoreOperation : : description ( ) const
{
2015-07-13 15:16:36 +01:00
if ( overwrittenPartition ( ) )
2016-07-17 23:41:00 +01:00
return xi18nc ( " @info:status " , " Restore partition from <filename>%1</filename> to <filename>%2</filename> " , fileName ( ) , overwrittenPartition ( ) - > deviceNode ( ) ) ;
2015-06-04 01:29:22 +01:00
2016-05-31 19:28:31 +01:00
return xi18nc ( " @info:status " , " Restore partition on <filename>%1</filename> at %2 from <filename>%3</filename> " , targetDevice ( ) . deviceNode ( ) , Capacity : : formatByteSize ( restorePartition ( ) . firstSector ( ) * targetDevice ( ) . logicalSize ( ) ) , fileName ( ) ) ;
2015-06-04 01:29:22 +01:00
}
void RestoreOperation : : setOverwrittenPartition ( Partition * p )
{
2015-07-13 15:16:36 +01:00
// This is copied from CopyOperation. One day we might create a common base class ;-)
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
cleanupOverwrittenPartition ( ) ;
m_OverwrittenPartition = p ;
m_MustDeleteOverwritten = ( p & & p - > state ( ) = = Partition : : StateNone ) ;
2015-06-04 01:29:22 +01:00
}
void RestoreOperation : : cleanupOverwrittenPartition ( )
{
2015-07-13 15:16:36 +01:00
if ( mustDeleteOverwritten ( ) ) {
delete overwrittenPartition ( ) ;
2015-07-22 14:48:03 +01:00
m_OverwrittenPartition = nullptr ;
2015-07-13 15:16:36 +01:00
}
2015-06-04 01:29:22 +01:00
}
/** Can a Partition be restored to somewhere?
2015-07-22 14:48:03 +01:00
@ param p the Partition in question , may be nullptr .
2015-07-13 15:16:36 +01:00
@ return true if a Partition can be restored to @ p p .
2015-06-04 01:29:22 +01:00
*/
bool RestoreOperation : : canRestore ( const Partition * p )
{
2015-07-22 14:48:03 +01:00
if ( p = = 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
if ( p - > isMounted ( ) )
return false ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( p - > roles ( ) . has ( PartitionRole : : Extended ) )
return false ;
2015-06-04 01:29:22 +01:00
2016-05-11 19:36:06 +01:00
if ( p - > roles ( ) . has ( PartitionRole : : Luks ) )
return FS : : luks : : mapperName ( p - > deviceNode ( ) ) . isEmpty ( ) ;
2015-07-13 15:16:36 +01:00
return true ;
2015-06-04 01:29:22 +01:00
}
/** Creates a new Partition to restore to.
2015-07-13 15:16:36 +01:00
@ param device the Device to create the Partition on
@ param parent the parent PartitionNode
@ param start start sector of the Partition
@ param filename name of the image file to restore from
2015-06-04 01:29:22 +01:00
*/
Partition * RestoreOperation : : createRestorePartition ( const Device & device , PartitionNode & parent , qint64 start , const QString & filename )
{
2015-07-13 15:16:36 +01:00
PartitionRole : : Roles r = PartitionRole : : Primary ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( ! parent . isRoot ( ) )
r = PartitionRole : : Logical ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
QFileInfo fileInfo ( filename ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( ! fileInfo . exists ( ) )
2015-07-22 14:48:03 +01:00
return nullptr ;
2015-06-04 01:29:22 +01:00
2016-05-31 19:28:31 +01:00
const qint64 end = start + fileInfo . size ( ) / device . logicalSize ( ) - 1 ;
2015-07-13 15:16:36 +01:00
Partition * p = new Partition ( & parent , device , PartitionRole ( r ) , FileSystemFactory : : create ( FileSystem : : Unknown , start , end ) , start , end , QString ( ) ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
p - > setState ( Partition : : StateRestore ) ;
return p ;
2015-06-04 01:29:22 +01:00
}