2011-02-21 16:30:31 +01:00
/**************************************************************************
* *
* * This file is part of Qt SDK * *
* *
* * Copyright ( c ) 2011 Nokia Corporation and / or its subsidiary ( - ies ) . *
* *
* * Contact : Nokia Corporation qt - info @ nokia . com * *
* *
* * No Commercial Usage
* *
* * This file contains pre - release code and may not be distributed .
* * You may use this file in accordance with the terms and conditions
* * contained in the Technology Preview License Agreement accompanying
* * this package .
* *
* * GNU Lesser General Public License Usage
* *
* * This file may be used under the terms of the GNU Lesser General Public
* * License version 2.1 as published by the Free Software Foundation and
* * appearing in the file LICENSE . LGPL included in the packaging of this file .
* * Please review the following information to ensure the GNU Lesser General
* * Public License version 2.1 requirements will be met :
* * http : //www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
* *
* * In addition , as a special exception , Nokia gives you certain additional
* * rights . These rights are described in the Nokia Qt LGPL Exception version
* * 1.1 , included in the file LGPL_EXCEPTION . txt in this package .
* *
* * If you are unsure which license is appropriate for your use , please contact
* * ( qt - info @ nokia . com ) .
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//#include "kdupdaterupdateoperations.h"
# include <KDUpdater/kdupdaterapplication.h>
# include <KDUpdater/kdupdaterpackagesinfo.h>
# include "createshortcutoperation.h"
# include "common/errors.h"
# include "common/fileutils.h"
# include "common/utils.h"
# include <QDir>
# include <QFileInfo>
# include <QTemporaryFile>
# include <algorithm>
# include <cerrno>
# ifdef Q_WS_WIN
# include <windows.h>
# include <shlobj.h>
# endif
using namespace QInstaller ;
2011-05-10 21:12:21 +02:00
static bool createLink ( QString fileName , QString linkName , QString workingDir , QString arguments = QString ( ) )
2011-02-21 16:30:31 +01:00
{
# ifdef Q_WS_WIN
bool ret = false ;
fileName = QDir : : toNativeSeparators ( fileName ) ;
linkName = QDir : : toNativeSeparators ( linkName ) ;
2011-05-10 21:12:21 +02:00
if ( workingDir . isEmpty ( ) )
2011-02-21 16:30:31 +01:00
workingDir = QFileInfo ( fileName ) . absolutePath ( ) ;
workingDir = QDir : : toNativeSeparators ( workingDir ) ;
//### assume that they add .lnk
IShellLink * psl ;
bool neededCoInit = false ;
HRESULT hres = CoCreateInstance ( CLSID_ShellLink , NULL , CLSCTX_INPROC_SERVER , IID_IShellLink , ( void * * ) & psl ) ;
if ( hres = = CO_E_NOTINITIALIZED ) { // COM was not initialized
neededCoInit = true ;
CoInitialize ( NULL ) ;
hres = CoCreateInstance ( CLSID_ShellLink , NULL , CLSCTX_INPROC_SERVER , IID_IShellLink , ( void * * ) & psl ) ;
}
if ( SUCCEEDED ( hres ) ) {
hres = psl - > SetPath ( ( wchar_t * ) fileName . utf16 ( ) ) ;
2011-05-10 21:12:21 +02:00
if ( SUCCEEDED ( hres ) & & ! arguments . isNull ( ) )
hres = psl - > SetArguments ( ( wchar_t * ) arguments . utf16 ( ) ) ;
2011-02-21 16:30:31 +01:00
if ( SUCCEEDED ( hres ) ) {
hres = psl - > SetWorkingDirectory ( ( wchar_t * ) workingDir . utf16 ( ) ) ;
if ( SUCCEEDED ( hres ) ) {
IPersistFile * ppf ;
hres = psl - > QueryInterface ( IID_IPersistFile , ( void * * ) & ppf ) ;
if ( SUCCEEDED ( hres ) ) {
hres = ppf - > Save ( ( wchar_t * ) linkName . utf16 ( ) , TRUE ) ;
if ( SUCCEEDED ( hres ) )
ret = true ;
ppf - > Release ( ) ;
}
}
}
psl - > Release ( ) ;
}
if ( neededCoInit )
CoUninitialize ( ) ;
return ret ;
# else
2011-05-10 21:12:21 +02:00
Q_UNUSED ( workingDir )
Q_UNUSED ( arguments )
return QFile : : link ( fileName , linkName ) ;
2011-02-21 16:30:31 +01:00
# endif
}
/*
TRANSLATOR QInstaller : : CreateShortcutOperation
*/
CreateShortcutOperation : : CreateShortcutOperation ( )
{
2011-05-10 21:12:21 +02:00
setName ( QLatin1String ( " CreateShortcut " ) ) ;
2011-02-21 16:30:31 +01:00
}
CreateShortcutOperation : : ~ CreateShortcutOperation ( )
{
2011-05-10 21:12:21 +02:00
deleteFileNowOrLater ( value ( QLatin1String ( " backupOfExistingShortcut " ) ) . toString ( ) ) ;
2011-02-21 16:30:31 +01:00
}
2011-05-10 21:12:21 +02:00
static bool isWorkingDirOption ( const QString & s ) {
return s . startsWith ( QLatin1String ( " workingDirectory= " ) ) ;
2011-02-21 16:30:31 +01:00
}
2011-05-10 21:12:21 +02:00
static QString getWorkingDir ( QStringList & args ) {
2011-02-21 16:30:31 +01:00
QString workingDir ;
// if the args contain an option in the form "workingDirectory=...", find it and consume it
2011-05-10 21:12:21 +02:00
QStringList : : iterator wdiropt = std : : find_if ( args . begin ( ) , args . end ( ) , isWorkingDirOption ) ;
if ( wdiropt ! = args . end ( ) ) {
workingDir = wdiropt - > mid ( QString : : fromLatin1 ( " workingDirectory= " ) . size ( ) ) ;
args . erase ( wdiropt ) ;
2011-02-21 16:30:31 +01:00
}
return workingDir ;
}
void CreateShortcutOperation : : backup ( )
{
QStringList args = this - > arguments ( ) ;
2011-05-10 21:12:21 +02:00
getWorkingDir ( args ) ; //consume workingDirectory= option
2011-02-21 16:30:31 +01:00
2011-05-10 21:12:21 +02:00
const QString path = QDir : : fromNativeSeparators ( QFileInfo ( args . at ( 1 ) ) . absolutePath ( ) ) ;
2011-02-21 16:30:31 +01:00
//verbose() << "dir to create shortcut in " << path << std::endl;
QDir createdDir = QDir : : root ( ) ;
// find out, which part of the path is the first one we actually need to create
int end = 0 ;
QStringList directoriesToCreate ;
2011-05-10 21:12:21 +02:00
while ( true ) {
QString p = path . section ( QLatin1String ( " / " ) , 0 , + + end ) ;
createdDir = QDir ( p ) ;
if ( ! createdDir . exists ( ) ) {
directoriesToCreate . push_back ( QDir : : toNativeSeparators ( createdDir . absolutePath ( ) ) ) ;
verbose ( ) < < " backup created dir_pre " < < QDir : : toNativeSeparators ( createdDir . absolutePath ( ) ) < < std : : endl ;
if ( p = = path )
2011-02-21 16:30:31 +01:00
break ;
2011-05-10 21:12:21 +02:00
} else if ( p = = path ) {
2011-02-21 16:30:31 +01:00
// everything did already exist -> nothing to do for us (nothing to revert then, either)
createdDir = QDir : : root ( ) ;
break ;
}
}
verbose ( ) < < " backup created dir " < < createdDir . absolutePath ( ) < < std : : endl ;
2011-05-10 21:12:21 +02:00
setValue ( QLatin1String ( " createddirs " ) , directoriesToCreate ) ;
2011-02-21 16:30:31 +01:00
//link creation context
2011-05-10 21:12:21 +02:00
const QString linkLocation = arguments ( ) [ 1 ] ;
if ( ! QFile : : exists ( linkLocation ) )
2011-02-21 16:30:31 +01:00
return ;
try {
2011-05-10 21:12:21 +02:00
setValue ( QLatin1String ( " backupOfExistingShortcut " ) , generateTemporaryFileName ( linkLocation ) ) ;
} catch ( const QInstaller : : Error & e ) {
setErrorString ( e . message ( ) ) ;
2011-02-21 16:30:31 +01:00
return ;
}
2011-05-10 21:12:21 +02:00
QFile f ( linkLocation ) ;
if ( ! f . copy ( value ( QLatin1String ( " backupOfExistingShortcut " ) ) . toString ( ) ) )
setErrorString ( QObject : : tr ( " Could not backup file %1: %2 " ) . arg ( linkLocation , f . errorString ( ) ) ) ;
2011-02-21 16:30:31 +01:00
}
bool CreateShortcutOperation : : performOperation ( )
{
QStringList args = this - > arguments ( ) ;
2011-05-10 21:12:21 +02:00
const QString workingDir = getWorkingDir ( args ) ;
2011-02-21 16:30:31 +01:00
2011-05-10 21:12:21 +02:00
if ( args . count ( ) ! = 2 & & args . count ( ) ! = 3 ) {
setError ( InvalidArguments ) ;
setErrorString ( QObject : : tr ( " Invalid arguments: %1 arguments given, 2 or 3 expected (optional: \" workingDirectory=... \" ). " ) . arg ( args . count ( ) ) ) ;
2011-02-21 16:30:31 +01:00
return false ;
}
2011-05-10 21:12:21 +02:00
const QString & linkTarget = args . at ( 0 ) ;
const QString & linkLocation = args . at ( 1 ) ;
const QString targetArguments = args . count ( ) = = 3 ? args [ 2 ] : QString ( ) ;
2011-02-21 16:30:31 +01:00
2011-05-10 21:12:21 +02:00
const QString dirName = QFileInfo ( linkLocation ) . absolutePath ( ) ;
2011-02-21 16:30:31 +01:00
//verbose() << "dir to create shortcut in " << dirName << std::endl;
errno = 0 ;
2011-05-10 21:12:21 +02:00
const bool dirAlreadyExists = QDir ( dirName ) . exists ( ) ;
2011-02-21 16:30:31 +01:00
const bool created = dirAlreadyExists | | QDir : : root ( ) . mkpath ( dirName ) ;
2011-05-10 21:12:21 +02:00
if ( ! created ) {
setError ( UserDefinedError ) ;
setErrorString ( tr ( " Could not create folder %1: %2. " ) . arg ( QDir : : toNativeSeparators ( dirName ) , QLatin1String ( strerror ( errno ) ) ) ) ;
2011-02-21 16:30:31 +01:00
return false ;
}
2011-05-10 21:12:21 +02:00
TempDirDeleter deleter ( dirName ) ;
2011-02-21 16:30:31 +01:00
2011-05-10 21:12:21 +02:00
if ( dirAlreadyExists )
2011-02-21 16:30:31 +01:00
deleter . releaseAll ( ) ;
#if 0 // disabled for now, isDir() also returns true if the link exists and points to a folder, then removing it fails
// link creation
2011-05-10 21:12:21 +02:00
if ( QFileInfo ( linkLocation ) . isDir ( ) ) {
2011-02-21 16:30:31 +01:00
errno = 0 ;
2011-05-10 21:12:21 +02:00
if ( ! QDir ( ) . rmdir ( linkLocation ) ) {
setError ( UserDefinedError ) ;
setErrorString ( QObject : : tr ( " Could not create link: failed to remove folder %1: %2 " ) . arg ( QDir : : toNativeSeparators ( linkLocation ) , QLatin1String ( strerror ( errno ) ) ) ) ;
2011-02-21 16:30:31 +01:00
return false ;
}
}
# endif
2011-05-10 21:12:21 +02:00
QString errorString ;
2011-02-21 16:30:31 +01:00
2011-05-10 21:12:21 +02:00
if ( QFile : : exists ( linkLocation ) & & ! deleteFileNowOrLater ( linkLocation , & errorString ) ) {
setError ( UserDefinedError ) ;
setErrorString ( QObject : : tr ( " Failed to overwrite %1: %2 " ) . arg ( QDir : : toNativeSeparators ( linkLocation ) , errorString ) ) ;
2011-02-21 16:30:31 +01:00
return false ;
}
2011-05-10 21:12:21 +02:00
const bool linked = createLink ( linkTarget , linkLocation , workingDir , targetArguments ) ;
if ( ! linked ) {
setError ( UserDefinedError ) ;
setErrorString ( tr ( " Could not create link %1: %2 " ) . arg ( QDir : : toNativeSeparators ( linkLocation ) , qt_error_string ( ) ) ) ;
2011-02-21 16:30:31 +01:00
return false ;
}
deleter . releaseAll ( ) ;
return true ;
}
bool CreateShortcutOperation : : undoOperation ( )
{
const QString linkLocation = arguments ( ) [ 1 ] ;
const QStringList args = this - > arguments ( ) ;
verbose ( ) < < " undo Shortcutoperation with arguments " ;
2011-05-10 21:12:21 +02:00
Q_FOREACH ( const QString & val , args )
2011-02-21 16:30:31 +01:00
verbose ( ) < < val < < " " ;
verbose ( ) < < std : : endl ;
// first remove the link
2011-05-10 21:12:21 +02:00
if ( ! deleteFileNowOrLater ( linkLocation ) ) {
setErrorString ( QObject : : tr ( " Could not delete file %1 " ) . arg ( linkLocation ) ) ;
2011-02-21 16:30:31 +01:00
return false ;
}
verbose ( ) < < " link has been deleted " < < std : : endl ;
2011-05-10 21:12:21 +02:00
if ( hasValue ( QLatin1String ( " backupOfExistingShortcut " ) ) ) {
const QString backupOfExistingShortcut = value ( QLatin1String ( " backupOfExistingShortcut " ) ) . toString ( ) ;
const bool success = QFile : : copy ( backupOfExistingShortcut , linkLocation ) & & deleteFileNowOrLater ( backupOfExistingShortcut ) ;
if ( ! success ) {
setErrorString ( QObject : : tr ( " Could not restore backup file into %1 " ) . arg ( linkLocation ) ) ;
2011-02-21 16:30:31 +01:00
return success ;
}
}
verbose ( ) < < " got behin backup " < < std : : endl ;
2011-05-10 21:12:21 +02:00
const QStringList createdDirsPaths = value ( QLatin1String ( " createddirs " ) ) . toStringList ( ) ;
if ( createdDirsPaths . isEmpty ( ) ) //no dir to delete (QDir(createdDirPath) would return the current working directory -> never do that
2011-02-21 16:30:31 +01:00
return true ;
2011-05-10 21:12:21 +02:00
const bool forceremoval = QVariant ( value ( QLatin1String ( " forceremoval " ) ) ) . toBool ( ) ;
QListIterator < QString > it ( createdDirsPaths ) ;
for ( it . toBack ( ) ; it . hasPrevious ( ) ; ) {
2011-02-21 16:30:31 +01:00
const QString createdDirPath = it . previous ( ) ;
2011-05-10 21:12:21 +02:00
const QDir createdDir = QDir ( createdDirPath ) ;
2011-02-21 16:30:31 +01:00
verbose ( ) < < createdDir . absolutePath ( ) < < std : : endl ;
2011-05-10 21:12:21 +02:00
if ( createdDir = = QDir : : root ( ) )
2011-02-21 16:30:31 +01:00
return true ;
QString errorString ;
2011-05-10 21:12:21 +02:00
if ( forceremoval ) {
2011-02-21 16:30:31 +01:00
verbose ( ) < < " forced removal of path " < < createdDir . path ( ) < < std : : endl ;
try {
2011-05-10 21:12:21 +02:00
removeDirectory ( createdDir . path ( ) , false ) ;
} catch ( const QInstaller : : Error e ) {
setError ( UserDefinedError , e . message ( ) ) ;
2011-02-21 16:30:31 +01:00
return false ;
}
2011-05-10 21:12:21 +02:00
} else {
2011-02-21 16:30:31 +01:00
// even remove some hidden, OS-created files in there
# if defined Q_WS_MAC
2011-05-10 21:12:21 +02:00
QFile : : remove ( createdDir . path ( ) + QLatin1String ( " /.DS_Store " ) ) ;
2011-02-21 16:30:31 +01:00
# elif defined Q_WS_WIN
2011-05-10 21:12:21 +02:00
QFile : : remove ( createdDir . path ( ) + QLatin1String ( " /Thumbs.db " ) ) ;
2011-02-21 16:30:31 +01:00
# endif
errno = 0 ;
verbose ( ) < < " removal of path " < < createdDir . path ( ) < < std : : endl ;
2011-05-10 21:12:21 +02:00
const bool result = QDir : : root ( ) . rmdir ( createdDir . path ( ) ) ;
if ( ! result ) {
if ( errorString . isEmpty ( ) )
setError ( UserDefinedError , tr ( " Cannot remove directory %1: %2 " ) . arg ( createdDir . path ( ) , errorString ) ) ;
2011-02-21 16:30:31 +01:00
else
2011-05-10 21:12:21 +02:00
setError ( UserDefinedError , tr ( " Cannot remove directory %1: %2 " ) . arg ( createdDir . path ( ) , QLatin1String ( strerror ( errno ) ) ) ) ;
2011-02-21 16:30:31 +01:00
return result ;
}
}
}
return true ;
}
bool CreateShortcutOperation : : testOperation ( )
{
return true ;
}
CreateShortcutOperation * CreateShortcutOperation : : clone ( ) const
{
return new CreateShortcutOperation ( ) ;
}