2015-06-04 01:29:22 +01:00
/*************************************************************************
* Copyright ( C ) 2008 , 2009 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 "fs/ntfs.h"
# include "util/externalcommand.h"
# include "util/capacity.h"
# include "util/report.h"
# include "util/globallog.h"
# include <KLocalizedString>
2016-05-12 16:37:37 +01:00
# include <QRegularExpression>
2015-06-04 01:29:22 +01:00
# include <QString>
# include <QStringList>
# include <QFile>
# include <QUuid>
2016-05-11 22:27:40 +01:00
# include <algorithm>
2016-05-12 16:37:37 +01:00
# include <ctime>
2015-06-04 01:29:22 +01:00
namespace FS
{
2015-07-13 15:16:36 +01:00
FileSystem : : CommandSupportType ntfs : : m_GetUsed = FileSystem : : cmdSupportNone ;
FileSystem : : CommandSupportType ntfs : : m_GetLabel = FileSystem : : cmdSupportNone ;
FileSystem : : CommandSupportType ntfs : : m_Create = FileSystem : : cmdSupportNone ;
FileSystem : : CommandSupportType ntfs : : m_Grow = FileSystem : : cmdSupportNone ;
FileSystem : : CommandSupportType ntfs : : m_Shrink = FileSystem : : cmdSupportNone ;
FileSystem : : CommandSupportType ntfs : : m_Move = FileSystem : : cmdSupportNone ;
FileSystem : : CommandSupportType ntfs : : m_Check = FileSystem : : cmdSupportNone ;
FileSystem : : CommandSupportType ntfs : : m_Copy = FileSystem : : cmdSupportNone ;
FileSystem : : CommandSupportType ntfs : : m_Backup = FileSystem : : cmdSupportNone ;
FileSystem : : CommandSupportType ntfs : : m_SetLabel = FileSystem : : cmdSupportNone ;
FileSystem : : CommandSupportType ntfs : : m_UpdateUUID = FileSystem : : cmdSupportNone ;
FileSystem : : CommandSupportType ntfs : : m_GetUUID = FileSystem : : cmdSupportNone ;
ntfs : : ntfs ( qint64 firstsector , qint64 lastsector , qint64 sectorsused , const QString & label ) :
2018-04-07 19:54:30 +01:00
FileSystem ( firstsector , lastsector , sectorsused , label , FileSystem : : Type : : Ntfs )
2015-07-13 15:16:36 +01:00
{
}
void ntfs : : init ( )
{
m_Shrink = m_Grow = m_Check = m_GetUsed = findExternal ( QStringLiteral ( " ntfsresize " ) ) ? cmdSupportFileSystem : cmdSupportNone ;
m_GetLabel = cmdSupportCore ;
m_SetLabel = findExternal ( QStringLiteral ( " ntfslabel " ) ) ? cmdSupportFileSystem : cmdSupportNone ;
m_Create = findExternal ( QStringLiteral ( " mkfs.ntfs " ) ) ? cmdSupportFileSystem : cmdSupportNone ;
m_Copy = findExternal ( QStringLiteral ( " ntfsclone " ) ) ? cmdSupportFileSystem : cmdSupportNone ;
m_Backup = cmdSupportCore ;
2016-03-11 00:31:30 +00:00
m_UpdateUUID = cmdSupportCore ;
2015-07-13 15:16:36 +01:00
m_Move = ( m_Check ! = cmdSupportNone ) ? cmdSupportCore : cmdSupportNone ;
m_GetUUID = cmdSupportCore ;
}
bool ntfs : : supportToolFound ( ) const
{
return
m_GetUsed ! = cmdSupportNone & &
m_GetLabel ! = cmdSupportNone & &
m_SetLabel ! = cmdSupportNone & &
m_Create ! = cmdSupportNone & &
m_Check ! = cmdSupportNone & &
m_UpdateUUID ! = cmdSupportNone & &
m_Grow ! = cmdSupportNone & &
m_Shrink ! = cmdSupportNone & &
m_Copy ! = cmdSupportNone & &
m_Move ! = cmdSupportNone & &
m_Backup ! = cmdSupportNone & &
m_GetUUID ! = cmdSupportNone ;
}
FileSystem : : SupportTool ntfs : : supportToolName ( ) const
{
return SupportTool ( QStringLiteral ( " ntfs-3g " ) , QUrl ( QStringLiteral ( " http://www.tuxera.com/community/ntfs-3g-download/ " ) ) ) ;
}
qint64 ntfs : : minCapacity ( ) const
{
2018-04-09 15:14:34 +01:00
return 2 * Capacity : : unitFactor ( Capacity : : Unit : : Byte , Capacity : : Unit : : MiB ) ;
2015-07-13 15:16:36 +01:00
}
qint64 ntfs : : maxCapacity ( ) const
{
2018-04-09 15:14:34 +01:00
return 256 * Capacity : : unitFactor ( Capacity : : Unit : : Byte , Capacity : : Unit : : TiB ) ;
2015-07-13 15:16:36 +01:00
}
2017-09-11 16:52:20 +01:00
int ntfs : : maxLabelLength ( ) const
2015-07-13 15:16:36 +01:00
{
return 128 ;
}
qint64 ntfs : : readUsedCapacity ( const QString & deviceNode ) const
{
2016-04-21 22:48:05 +01:00
ExternalCommand cmd ( QStringLiteral ( " ntfsresize " ) , { QStringLiteral ( " --info " ) , QStringLiteral ( " --force " ) , QStringLiteral ( " --no-progress-bar " ) , deviceNode } ) ;
2015-07-13 15:16:36 +01:00
2016-05-12 16:37:37 +01:00
if ( cmd . run ( - 1 ) & & cmd . exitCode ( ) = = 0 ) {
2015-07-13 15:16:36 +01:00
qint64 usedBytes = - 1 ;
2016-05-12 16:37:37 +01:00
QRegularExpression re ( QStringLiteral ( " resize at ( \\ d+) bytes " )) ;
QRegularExpressionMatch reUsedBytes = re . match ( cmd . output ( ) ) ;
2015-07-13 15:16:36 +01:00
2016-05-12 16:37:37 +01:00
if ( reUsedBytes . hasMatch ( ) )
usedBytes = reUsedBytes . captured ( 1 ) . toLongLong ( ) ;
2015-07-13 15:16:36 +01:00
if ( usedBytes > - 1 )
return usedBytes ;
}
return - 1 ;
}
bool ntfs : : writeLabel ( Report & report , const QString & deviceNode , const QString & newLabel )
{
2017-11-07 22:55:28 +00:00
ExternalCommand writeCmd ( report , QStringLiteral ( " ntfslabel " ) , { QStringLiteral ( " --force " ) , deviceNode , newLabel } , QProcess : : SeparateChannels ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
if ( ! writeCmd . run ( - 1 ) )
return false ;
2015-06-04 01:29:22 +01:00
2016-05-05 12:46:27 +01:00
return true ;
2015-07-13 15:16:36 +01:00
}
bool ntfs : : check ( Report & report , const QString & deviceNode ) const
{
2016-04-21 22:48:05 +01:00
ExternalCommand cmd ( report , QStringLiteral ( " ntfsresize " ) , { QStringLiteral ( " --no-progress-bar " ) , QStringLiteral ( " --info " ) , QStringLiteral ( " --force " ) , QStringLiteral ( " --verbose " ) , deviceNode } ) ;
2015-07-13 15:16:36 +01:00
return cmd . run ( - 1 ) & & cmd . exitCode ( ) = = 0 ;
}
2015-06-04 01:29:22 +01:00
2016-09-05 12:10:56 +01:00
bool ntfs : : create ( Report & report , const QString & deviceNode )
2015-07-13 15:16:36 +01:00
{
2016-04-21 22:48:05 +01:00
ExternalCommand cmd ( report , QStringLiteral ( " mkfs.ntfs " ) , { QStringLiteral ( " --quick " ) , QStringLiteral ( " --verbose " ) , deviceNode } ) ;
2015-07-13 15:16:36 +01:00
return cmd . run ( - 1 ) & & cmd . exitCode ( ) = = 0 ;
}
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
bool ntfs : : copy ( Report & report , const QString & targetDeviceNode , const QString & sourceDeviceNode ) const
{
2016-04-21 22:48:05 +01:00
ExternalCommand cmd ( report , QStringLiteral ( " ntfsclone " ) , { QStringLiteral ( " --force " ) , QStringLiteral ( " --overwrite " ) , targetDeviceNode , sourceDeviceNode } ) ;
2015-06-04 01:29:22 +01:00
2015-07-13 15:16:36 +01:00
return cmd . run ( - 1 ) & & cmd . exitCode ( ) = = 0 ;
}
bool ntfs : : resize ( Report & report , const QString & deviceNode , qint64 length ) const
{
2016-04-21 22:48:05 +01:00
QStringList args = { QStringLiteral ( " --no-progress-bar " ) , QStringLiteral ( " --force " ) , deviceNode , QStringLiteral ( " --size " ) , QString : : number ( length ) } ;
2015-07-13 15:16:36 +01:00
QStringList dryRunArgs = args ;
2016-04-20 16:30:23 +01:00
dryRunArgs < < QStringLiteral ( " --no-action " ) ;
2015-07-13 15:16:36 +01:00
ExternalCommand cmdDryRun ( QStringLiteral ( " ntfsresize " ) , dryRunArgs ) ;
if ( cmdDryRun . run ( - 1 ) & & cmdDryRun . exitCode ( ) = = 0 ) {
ExternalCommand cmd ( report , QStringLiteral ( " ntfsresize " ) , args ) ;
return cmd . run ( - 1 ) & & cmd . exitCode ( ) = = 0 ;
}
return false ;
}
bool ntfs : : updateUUID ( Report & report , const QString & deviceNode ) const
{
2016-04-21 22:50:19 +01:00
Q_UNUSED ( report ) ;
2016-04-22 13:30:19 +01:00
ExternalCommand cmd ( QStringLiteral ( " ntfslabel " ) , { QStringLiteral ( " --new-serial " ) , deviceNode } ) ;
2015-07-13 15:16:36 +01:00
2016-04-22 13:30:19 +01:00
return cmd . run ( - 1 ) & & cmd . exitCode ( ) = = 0 ;
2015-07-13 15:16:36 +01:00
}
bool ntfs : : updateBootSector ( Report & report , const QString & deviceNode ) const
{
2016-07-17 23:41:00 +01:00
report . line ( ) < < xi18nc ( " @info:progress " , " Updating boot sector for NTFS file system on partition <filename>%1</filename>. " , deviceNode ) ;
2015-07-13 15:16:36 +01:00
2017-09-11 00:29:30 +01:00
qint64 n = firstSector ( ) ;
2015-07-13 15:16:36 +01:00
char * s = reinterpret_cast < char * > ( & n ) ;
2015-06-04 01:29:22 +01:00
# if Q_BYTE_ORDER == Q_BIG_ENDIAN
2015-07-13 15:16:36 +01:00
std : : swap ( s [ 0 ] , s [ 3 ] ) ;
std : : swap ( s [ 1 ] , s [ 2 ] ) ;
2015-06-04 01:29:22 +01:00
# endif
2017-12-10 17:32:02 +00:00
ExternalCommand cmd ( report , QStringLiteral ( " dd " ) , { QStringLiteral ( " of= " ) + deviceNode , QStringLiteral ( " bs=1 " ) , QStringLiteral ( " count=4 " ) , QStringLiteral ( " seek=28 " ) } ) ;
2015-07-13 15:16:36 +01:00
2017-12-10 17:37:10 +00:00
cmd . write ( QByteArray ( s , sizeof ( s ) ) ) ;
2017-12-10 17:32:02 +00:00
if ( ! cmd . start ( ) ) {
Log ( ) < < xi18nc ( " @info:progress " , " Could not write new start sector to partition <filename>%1</filename> when trying to update the NTFS boot sector. " , deviceNode ) ;
2015-07-13 15:16:36 +01:00
return false ;
}
2017-12-10 17:32:02 +00:00
cmd . waitFor ( - 1 ) ;
// Also update backup NTFS boot sector located at the end of the partition
// NOTE: this should fail if filesystem does not span the whole partition
qint64 pos = ( lastSector ( ) - firstSector ( ) ) * sectorSize ( ) + 28 ;
ExternalCommand cmd2 ( report , QStringLiteral ( " dd " ) , { QStringLiteral ( " of= " ) + deviceNode , QStringLiteral ( " bs=1 " ) , QStringLiteral ( " count=4 " ) , QStringLiteral ( " seek= " ) + QString : : number ( pos ) } ) ;
2015-07-13 15:16:36 +01:00
2017-12-10 17:37:10 +00:00
cmd2 . write ( QByteArray ( s , sizeof ( s ) ) ) ;
2017-12-10 17:32:02 +00:00
if ( ! cmd2 . start ( ) ) {
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:progress " , " Could not write new start sector to partition <filename>%1</filename> when trying to update the NTFS boot sector. " , deviceNode ) ;
2015-07-13 15:16:36 +01:00
return false ;
}
2017-12-10 17:32:02 +00:00
cmd2 . waitFor ( - 1 ) ;
2015-07-13 15:16:36 +01:00
2016-07-17 23:41:00 +01:00
Log ( ) < < xi18nc ( " @info:progress " , " Updated NTFS boot sector for partition <filename>%1</filename> successfully. " , deviceNode ) ;
2015-07-13 15:16:36 +01:00
return true ;
}
2015-06-04 01:29:22 +01:00
}